Skip to content

Commit

Permalink
Merge branch 'main' into omri374/dicom/pipenv_lock
Browse files Browse the repository at this point in the history
  • Loading branch information
omri374 authored Jul 6, 2023
2 parents 46d4a8a + 08e7b89 commit de53cb7
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ def verify_dicom_instance(
"""
instance_copy = deepcopy(instance)

try:
instance_copy.PixelData
except AttributeError:
raise AttributeError("Provided DICOM instance lacks pixel data.")

# Load image for processing
with tempfile.TemporaryDirectory() as tmpdirname:
# Convert DICOM to PNG and add padding for OCR (during analysis)
Expand All @@ -86,8 +91,8 @@ def verify_dicom_instance(
ocr_results = self.ocr_engine.perform_ocr(image)
analyzer_results = self.image_analyzer_engine.analyze(
image,
ad_hoc_recognizers=[deny_list_recognizer],
ocr_kwargs=ocr_kwargs,
ad_hoc_recognizers=[deny_list_recognizer],
**text_analyzer_kwargs,
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import uuid
import shutil
from copy import deepcopy
import tempfile
Expand Down Expand Up @@ -49,18 +50,24 @@ def redact(
:return: DICOM instance with redacted pixel data.
"""
# Check input
if type(image) != pydicom.dataset.FileDataset:
if type(image) not in [pydicom.dataset.FileDataset, pydicom.dataset.Dataset]:
raise TypeError("The provided image must be a loaded DICOM instance.")
try:
image.PixelData
except AttributeError:
raise AttributeError("Provided DICOM instance lacks pixel data.")

instance = deepcopy(image)

# Load image for processing
with tempfile.TemporaryDirectory() as tmpdirname:
# Convert DICOM to PNG and add padding for OCR (during analysis)
is_greyscale = self._check_if_greyscale(instance)
image = self._rescale_dcm_pixel_array(instance, is_greyscale)
self._save_pixel_array_as_png(image, is_greyscale, "tmp_dcm", tmpdirname)
image_name = str(uuid.uuid4())
self._save_pixel_array_as_png(image, is_greyscale, image_name, tmpdirname)

png_filepath = f"{tmpdirname}/tmp_dcm.png"
png_filepath = f"{tmpdirname}/{image_name}.png"
loaded_image = Image.open(png_filepath)
image = self._add_padding(loaded_image, is_greyscale, padding_width)

Expand All @@ -72,8 +79,8 @@ def redact(
)
analyzer_results = self.image_analyzer_engine.analyze(
image,
ad_hoc_recognizers=[deny_list_recognizer],
ocr_kwargs=ocr_kwargs,
ad_hoc_recognizers=[deny_list_recognizer],
**text_analyzer_kwargs,
)

Expand Down Expand Up @@ -225,8 +232,11 @@ def _check_if_greyscale(instance: pydicom.dataset.FileDataset) -> bool:
:return: FALSE if the Photometric Interpretation is RGB.
"""
# Check if image is grayscale using the Photometric Interpretation element
color_scale = instance[0x0028, 0x0004].value
is_greyscale = color_scale != "RGB"
try:
color_scale = instance.PhotometricInterpretation
except AttributeError:
color_scale = None
is_greyscale = (color_scale in ["MONOCHROME1", "MONOCHROME2"])

return is_greyscale

Expand All @@ -243,7 +253,10 @@ def _rescale_dcm_pixel_array(
"""
# Normalize contrast
if "WindowWidth" in instance:
image_2d = apply_voi_lut(instance.pixel_array, instance)
if is_greyscale:
image_2d = apply_voi_lut(instance.pixel_array, instance)
else:
image_2d = instance.pixel_array
else:
image_2d = instance.pixel_array

Expand Down Expand Up @@ -814,6 +827,11 @@ def _redact_single_dicom_image(
# Load instance
instance = pydicom.dcmread(dst_path)

try:
instance.PixelData
except AttributeError:
raise AttributeError("Provided DICOM file lacks pixel data.")

# Load image for processing
with tempfile.TemporaryDirectory() as tmpdirname:
# Convert DICOM to PNG and add padding for OCR (during analysis)
Expand All @@ -830,8 +848,8 @@ def _redact_single_dicom_image(
)
analyzer_results = self.image_analyzer_engine.analyze(
image,
ad_hoc_recognizers=[deny_list_recognizer],
ocr_kwargs=ocr_kwargs,
ad_hoc_recognizers=[deny_list_recognizer],
**text_analyzer_kwargs,
)

Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Unit tests for dicom_image_pii_verify_engine
"""
from copy import deepcopy
import pydicom

from presidio_image_redactor import (
Expand Down Expand Up @@ -121,6 +122,28 @@ def test_verify_dicom_instance_happy_path(
assert mock_analyze.call_count == 1
assert mock_verify.call_count == 1

def test_verify_dicom_instance_exception(
mock_engine: DicomImagePiiVerifyEngine,
get_mock_dicom_instance: pydicom.dataset.FileDataset,
):
"""Test exceptions for DicomImagePiiVerifyEngine.verify_dicom_instance
Args:
mock_engine (DicomImagePiiVerifyEngine): Instantiated engine.
get_mock_dicom_instance (pydicom.dataset.FileDataset): Loaded DICOM.
"""
with pytest.raises(Exception) as exc_info:
# Arrange
padding_width = 25
test_instance = deepcopy(get_mock_dicom_instance)
del test_instance.PixelData
expected_error_type = AttributeError

# Act
_, _, _ = mock_engine.verify_dicom_instance(test_instance, padding_width)

# Assert
assert expected_error_type == exc_info.typename


# ------------------------------------------------------
# DicomImagePiiVerifyEngine.eval_dicom_instance()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def mock_engine():
Path(TEST_DICOM_PARENT_DIR),
[
Path(TEST_DICOM_PARENT_DIR, "0_ORIGINAL.dcm"),
Path(TEST_DICOM_PARENT_DIR, "0_ORIGINAL_compressed.dcm"),
Path(TEST_DICOM_PARENT_DIR, "0_ORIGINAL_no_pixels.dcm"),
Path(TEST_DICOM_PARENT_DIR, "RGB_ORIGINAL.dcm"),
Path(TEST_DICOM_DIR_2, "1_ORIGINAL.DCM"),
Path(TEST_DICOM_DIR_2, "2_ORIGINAL.dicom"),
Expand Down Expand Up @@ -1208,7 +1208,8 @@ def test_DicomImageRedactorEngine_redact_happy_path(
(Path(TEST_DICOM_PARENT_DIR), "TypeError"),
("path_here", "TypeError"),
(np.random.randint(255, size=(64, 64)), "TypeError"),
(Image.fromarray(np.random.randint(255, size=(400, 400),dtype=np.uint8)), "TypeError")
(Image.fromarray(np.random.randint(255, size=(400, 400),dtype=np.uint8)), "TypeError"),
(pydicom.dcmread(Path(TEST_DICOM_PARENT_DIR, "0_ORIGINAL_no_pixels.dcm")), "AttributeError")
],
)
def test_DicomImageRedactorEngine_redact_exceptions(
Expand Down Expand Up @@ -1343,6 +1344,7 @@ def save_as(self, dst_path: str):
[
(Path(TEST_DICOM_PARENT_DIR), "FileNotFoundError"),
(Path("nonexistentfile.extension"), "FileNotFoundError"),
(Path(TEST_DICOM_PARENT_DIR, "0_ORIGINAL_no_pixels.dcm"), "AttributeError")
],
)
def test_DicomImageRedactorEngine_redact_single_dicom_image_exceptions(
Expand Down

0 comments on commit de53cb7

Please sign in to comment.