Ejemplo n.º 1
0
    def test_jitter_timestamp(self):

        from deid.dicom.actions import jitter_timestamp

        dicom = get_dicom(self.dataset)

        print("Testing test_jitter_timestamp")

        print("Case 1: Testing jitter_timestamp with DICOM Date (DA)")
        dicom.StudyDate = "20131210"
        dicom.data_element("StudyDate").VR = "DA"
        jitter_timestamp(dicom, "StudyDate", 10)
        expected = "20131220"
        self.assertEqual(dicom.StudyDate, expected)

        print("Case 2: Testing with DICOM timestamp (DT)")
        dicom.AcquisitionDateTime = "20131210081530"
        dicom.data_element("AcquisitionDateTime").VR = "DT"
        jitter_timestamp(dicom, "AcquisitionDateTime", 10)
        expected = "20131220081530.000000"
        self.assertEqual(dicom.AcquisitionDateTime, expected)

        print("Case 3: Testing with non-standard DICOM date (DA)")
        dicom.StudyDate = "2013/12/10"
        dicom.data_element("StudyDate").VR = "DA"
        jitter_timestamp(dicom, "StudyDate", 10)
        expected = "20131220"
        self.assertEqual(dicom.StudyDate, expected)

        print("Case 4: Testing negative jitter value")
        dicom.StudyDate = "20131210"
        jitter_timestamp(dicom, "StudyDate", -5)
        expected = "20131205"
        self.assertEqual(dicom.StudyDate, expected)

        print("Case 5: Testing with empty field")
        dicom.StudyDate = expected = ""
        jitter_timestamp(dicom, "StudyDate", 10)
        self.assertEqual(dicom.StudyDate, expected)

        print("Case 6: Testing with nonexistent field")
        del dicom.StudyDate
        jitter_timestamp(dicom, "StudyDate", 10)
        self.assertTrue("StudyDate" not in dicom)

        print("Case 7: Testing JITTER recipe action")
        from deid.dicom.actions import perform_action

        dicom.StudyDate = "20131210"
        dicom.data_element("StudyDate").VR = "DA"
        JITTER = {"action": "JITTER", "field": "StudyDate", "value": "-5"}
        expected = "20131205"
        dicom = perform_action(dicom=dicom, action=JITTER)
        self.assertTrue(dicom.StudyDate, expected)
Ejemplo n.º 2
0
def replace_identifiers(
    dicom_files,
    ids=None,
    deid=None,
    save=True,
    overwrite=False,
    output_folder=None,
    force=True,
    config=None,
    strip_sequences=True,
    remove_private=True,
):
    """replace identifiers using pydicom, can be slow when writing
       and saving new files. If you want to replace sequences, they need
       to be extracted with get_identifiers and expand_sequences to True.
    """
    dicom_files, recipe, config = _prepare_replace_config(dicom_files,
                                                          deid=deid,
                                                          config=config)

    # ids (a lookup) is not required
    ids = ids or {}

    # Parse through dicom files, update headers, and save
    updated_files = []
    for _, dicom_file in enumerate(dicom_files):

        if isinstance(dicom_file, Dataset):
            dicom = dicom_file
            dicom_file = dicom.filename
        else:
            dicom = read_file(dicom_file, force=force)
        dicom_name = os.path.basename(dicom_file)

        # Remove sequences first, maintained in DataStore
        if strip_sequences is True:
            dicom = remove_sequences(dicom)

        # Remove private tags at the onset, if requested
        if remove_private:
            try:
                dicom.remove_private_tags()
            except:
                bot.error(
                    """Private tags for %s could not be completely removed, usually
                             this is due to invalid data type. Removing others."""
                    % dicom_name)
                private_tags = get_private(dicom)
                for ptag in private_tags:
                    del dicom[ptag.tag]
                continue

        # Include private tags (if not removed) plus dicom.dir
        fields = dicom_dir(dicom)

        if recipe.deid is not None:

            if dicom_file not in ids:
                ids[dicom_file] = {}

            # Prepare additional lists of values and fields (updates item)
            if recipe.has_values_lists():
                for group, actions in recipe.get_values_lists().items():
                    ids[dicom_file][group] = extract_values_list(
                        dicom=dicom, actions=actions)

            if recipe.has_fields_lists():
                for group, actions in recipe.get_fields_lists().items():
                    ids[dicom_file][group] = extract_fields_list(
                        dicom=dicom, actions=actions)

            for action in recipe.get_actions():
                dicom = perform_action(dicom=dicom,
                                       item=ids[dicom_file],
                                       action=action)

        # Next perform actions in default config, only if not done
        for action in config["put"]["actions"]:
            if action["field"] in fields:
                dicom = perform_action(dicom=dicom, action=action)

        # Assemble a new dataset, again accounting for private tags
        ds = Dataset()
        for field in dicom_dir(dicom):

            try:
                # Most fields are strings
                if isinstance(field, str):
                    ds.add(dicom.data_element(field))

                # Remainder are tags
                else:
                    ds.add(dicom.get(field))
            except:
                pass

        # Copy original data attributes
        attributes = [
            "is_little_endian",
            "is_implicit_VR",
            "is_decompressed",
            "read_encoding",
            "read_implicit_vr",
            "read_little_endian",
            "_parent_encoding",
        ]

        # We aren't including preamble, we will reset to be empty 128 bytes
        ds.preamble = b"\0" * 128

        for attribute in attributes:
            if hasattr(dicom, attribute):
                ds.__setattr__(attribute, dicom.__getattribute__(attribute))

        # Original meta data                     # or default empty dataset
        file_metas = getattr(dicom, "file_meta", Dataset())

        # Media Storage SOP Instance UID can be identifying
        if hasattr(file_metas, "MediaStorageSOPInstanceUID"):
            file_metas.MediaStorageSOPInstanceUID = ""

        # Save meta data
        ds.file_meta = file_metas

        # Save to file?
        if save is True:
            ds = save_dicom(
                dicom=ds,
                dicom_file=dicom_file,
                output_folder=output_folder,
                overwrite=overwrite,
            )
        updated_files.append(ds)

    return updated_files
Ejemplo n.º 3
0
    def test_parse_action(self):
        print("Test test_parse_action")
        from deid.dicom.actions import perform_action
        dicom = get_dicom(self.dataset)

        print("Case 1: Testing ADD action")
        self.assertTrue("PatientIdentityRemoved" not in dicom)
        ADD = {
            "action": "ADD",
            "field": "PatientIdentityRemoved",
            "value": "Yes"
        }

        dicom = perform_action(dicom=dicom, action=ADD)
        self.assertTrue("PatientIdentityRemoved" in dicom)
        self.assertEqual(dicom.get("PatientIdentityRemoved"), "Yes")

        print("Case 2: Testing REPLACE action with string")
        REPLACE = {
            "action": "REPLACE",
            "field": "PatientIdentityRemoved",
            "value": "No"
        }

        dicom = perform_action(dicom=dicom, action=REPLACE)
        self.assertTrue("PatientIdentityRemoved" in dicom)
        self.assertEqual(dicom.get("PatientIdentityRemoved"), "No")

        print("Case 3: Testing REPLACE action with variable")
        item = {"fish": "stick"}
        REPLACE = {
            "action": "REPLACE",
            "field": "PatientIdentityRemoved",
            "value": "var:fish"
        }

        dicom = perform_action(dicom=dicom, action=REPLACE, item=item)
        self.assertEqual(dicom.get("PatientIdentityRemoved"), "stick")

        print("Case 4: Testing REPLACE action with non-existing variable")
        REPLACE = {
            "action": "REPLACE",
            "field": "PatientIdentityRemoved",
            "value": "var:gummybear"
        }
        before = dicom.get("PatientIdentityRemoved")
        updated = perform_action(dicom=dicom, action=REPLACE, item=item)
        self.assertEqual(updated, updated)
        after = dicom.get("PatientIdentityRemoved")
        self.assertEqual(before, after)

        print("Case 5: Testing REMOVE action")
        REMOVE = {"action": "REMOVE", "field": "PatientIdentityRemoved"}

        dicom = perform_action(dicom=dicom, action=REMOVE)
        self.assertTrue("PatientIdentityRemoved" not in dicom)

        print("Case 6: Testing invalid action")
        RUN = {"action": "RUN", "field": "PatientIdentityRemoved"}

        updated = perform_action(dicom=dicom, action=RUN)
        self.assertEqual(updated, updated)

        print("Case 7: Testing function (func:) with action")
        ACTION = {
            "action": "REPLACE",
            "field": "PatientID",
            "value": "func:generate_uid"
        }

        # Here is the function we define to replace
        def generate_uid(item, value, field):
            return "pancakes"

        # The function must be in the item lookup
        item['generate_uid'] = generate_uid

        updated = perform_action(dicom=dicom, action=ACTION, item=item)
        self.assertEqual(updated.PatientID, "pancakes")
Ejemplo n.º 4
0
    def test_parse_action(self):
        print("Test test_parse_action")
        from deid.dicom.actions import perform_action

        dicom = get_dicom(self.dataset)

        print("Case 1: Testing ADD action")
        self.assertTrue("PatientIdentityRemoved" not in dicom)
        ADD = {
            "action": "ADD",
            "field": "PatientIdentityRemoved",
            "value": "Yes"
        }

        dicom = perform_action(dicom=dicom, action=ADD)
        self.assertTrue("PatientIdentityRemoved" in dicom)
        self.assertEqual(dicom.get("PatientIdentityRemoved"), "Yes")

        print("Case 2: Testing REPLACE action with string")
        REPLACE = {
            "action": "REPLACE",
            "field": "PatientIdentityRemoved",
            "value": "No",
        }

        dicom = perform_action(dicom=dicom, action=REPLACE)
        self.assertTrue("PatientIdentityRemoved" in dicom)
        self.assertEqual(dicom.get("PatientIdentityRemoved"), "No")

        print("Case 3: Testing REPLACE action with variable")
        item = {"fish": "stick"}
        REPLACE = {
            "action": "REPLACE",
            "field": "PatientIdentityRemoved",
            "value": "var:fish",
        }

        dicom = perform_action(dicom=dicom, action=REPLACE, item=item)
        self.assertEqual(dicom.get("PatientIdentityRemoved"), "stick")

        print("Case 4: Testing REPLACE action with non-existing variable")
        REPLACE = {
            "action": "REPLACE",
            "field": "PatientIdentityRemoved",
            "value": "var:gummybear",
        }
        before = dicom.get("PatientIdentityRemoved")
        updated = perform_action(dicom=dicom, action=REPLACE, item=item)
        self.assertEqual(updated, updated)
        after = dicom.get("PatientIdentityRemoved")
        self.assertEqual(before, after)

        print("Case 5: Testing REMOVE action")
        REMOVE = {"action": "REMOVE", "field": "PatientIdentityRemoved"}

        dicom = perform_action(dicom=dicom, action=REMOVE)
        self.assertTrue("PatientIdentityRemoved" not in dicom)

        # Test a boolean remove, contains field stanford
        REMOVE = {
            "action": "REMOVE",
            "field": "ALL",
            "value": "func:is_stanford"
        }

        # Here is the function that returns a boolean to indicate if replace
        def is_stanford(item, value, field):
            return item.get(field) == "STANFORD"

        item = {"is_stanford": is_stanford}
        dicom = perform_action(dicom=dicom, action=REMOVE, item=item)
        self.assertTrue("InstitutionName" not in dicom)

        print("Case 6: Testing invalid action")
        RUN = {"action": "RUN", "field": "PatientIdentityRemoved"}

        updated = perform_action(dicom=dicom, action=RUN)
        self.assertEqual(updated, updated)

        print("Case 7: Testing function (func:) with action")
        ACTION = {
            "action": "REPLACE",
            "field": "PatientID",
            "value": "func:generate_uid",
        }

        # Here is the function we define to replace
        def generate_uid(item, value, field):
            return "pancakes"

        # The function must be in the item lookup
        item["generate_uid"] = generate_uid

        updated = perform_action(dicom=dicom, action=ACTION, item=item)
        self.assertEqual(updated.PatientID, "pancakes")

        # Test each of filters for contains, not contains, equals, etc.
        dicom = get_dicom(self.dataset)

        print("Testing contains, equals, and empty action with REMOVE")
        self.assertTrue("ReferringPhysicianName" in dicom)
        REMOVE = {"action": "REMOVE", "field": "ALL", "value": "contains:Dr."}
        dicom = perform_action(dicom=dicom, action=REMOVE)
        self.assertTrue("ReferringPhysicianName" not in dicom)

        self.assertTrue("InstitutionName" in dicom)
        REMOVE = {
            "action": "REMOVE",
            "field": "ALL",
            "value": "equals:STANFORD"
        }
        dicom = perform_action(dicom=dicom, action=REMOVE)
        self.assertTrue("InstitutionName" not in dicom)

        self.assertTrue("StudyID" in dicom)
        REMOVE = {"action": "REMOVE", "field": "ALL", "value": "empty"}
        dicom = perform_action(dicom=dicom, action=REMOVE)
        self.assertTrue("StudyID" not in dicom)