def pull_and_send(self, items: Iterable, source: Orthanc, domain: str, dest: Orthanc, anonymize=False): def mkq(d: Dixel): return {"StudyInstanceUID": d.tags["StudyInstanceUID"]} for d in items: sham_oid = ShamDixel.sham_oid(d) logging.debug(sham_oid) if dest.exists(sham_oid): logging.debug("SKIPPING {}".format(d.tags["PatientName"])) continue if not source.exists(d): source.rfind(mkq(d), domain, level=DicomLevel.STUDIES, retrieve=True) else: logging.debug("SKIPPING PULL for {}".format( d.tags["PatientName"])) replacement_map = ShamDixel.orthanc_sham_map(d) anon_id = source.anonymize(d, replacement_map=replacement_map) source.psend(anon_id, dest) source.delete(anon_id) source.delete(d)
def make_key(self, ids, source: Orthanc, domain: str) -> set: print("Making key") # Minimal data for oid and sham plus study and series desc def mkq(accession_num): return { "PatientName": "", "PatientID": "", "PatientBirthDate": "", "PatientSex": "", "AccessionNumber": accession_num, "StudyDescription": "", "StudyInstanceUID": "", "StudyDate": "", "StudyTime": "", } items = set() for id in ids: q = mkq(id) try: r = source.rfind(q, domain, level=DicomLevel.STUDIES) except: r = None if not r: print("Failed to collect an id") continue tags = { "PatientName": r[0]["PatientName"], "PatientID": r[0]["PatientID"], "PatientBirthDate": r[0]["PatientBirthDate"], "PatientSex": r[0]["PatientSex"], "AccessionNumber": r[0]["AccessionNumber"], "StudyDescription": r[0]["StudyDescription"], "StudyInstanceUID": r[0]["StudyInstanceUID"], "StudyDate": r[0]["StudyDate"], "StudyTime": r[0]["StudyTime"] } d = Dixel(tags=tags) e = ShamDixel.from_dixel(d) items.add(e) print("Found {} items".format(len(items))) logging.debug(e) return items
def test_csv(tmp_path): fp = tmp_path / "tmp.csv" ep0 = CsvFile(fp=fp) ep0.fieldnames = ["_Age", "PatientName", "AccessionNumber"] for i in range(10): tags = { "PatientName": "Subject {}".format(i), "AccessionNumber": "Study {}".format(i) } meta = { "Age": 20+i } ep0.dixels.add(Dixel(tags=tags, meta=meta)) ep0.write() ep1 = CsvFile(fp=fp) ep1.read() d = ep1.dixels.pop() logging.debug(d) assert( d.meta['Age']>="20" ) assert( d.tags['PatientName'].startswith("Subject")) logging.debug(ep1.fieldnames) ep2 = CsvFile(fp=fp) ep2.fieldnames = ['_ShamID', '_ShamBirthDate', '_ShamAccessionNumber', 'PatientName', 'AccessionNumber'] ShamDixel.REFERENCE_DATE = date(year=2018, month=1, day=1) for d in ep0.dixels: logging.debug(d) ep2.dixels.add( ShamDixel.from_dixel(d) ) ep2.write() ep2.fieldnames = "ALL" ep2.write() os.remove(fp)
def _handle_instance_in_dcm_dir(item: Dixel, orth: Orthanc, salt: str): orth.put(item) anon = ShamDixel.from_dixel(item, salt=salt) afile = orth.anonymize(anon, replacement_map=anon.orthanc_sham_map()) anon.file = afile orth.put(anon) orth.delete(item) anon_study_id = anon.sham_parent_oid(DCMLv.STUDIES) logging.debug(anon_study_id) logging.debug(tagged_studies) if anon_study_id not in tagged_studies: logging.debug("Tagging parent study: {}".format(anon_study_id)) siren_info = pack_siren_info(anon) orth.gateway.put_metadata(anon_study_id, DCMLv.STUDIES, "siren_info", siren_info) tagged_studies.append(anon_study_id)
def test_anon(setup_orthanc0): O = Orthanc() dicom_dir = find_resource("resources/dcm") D = DcmDir(path=dicom_dir) d = D.get("IM2263", view=DixelView.TAGS_FILE) O.put(d) d.tags["AccessionNumber"] = "123456" d.tags["PatientBirthDate"] = "20000101" d.tags["PatientID"] = "ABC" d.tags["PatientName"] = "XYZ" d.level = DicomLevel.STUDIES e = ShamDixel.from_dixel(d) rep = e.orthanc_sham_map() O.anonymize("959e4e9f-e954be4e-11917c87-09d0f98f-7cc39128", level=DicomLevel.STUDIES, replacement_map=rep)
def test_shams(): tags = { "PatientName": "FOOABC^BAR^Z", "PatientBirthDate": "20000101", "StudyDate": "20180102", "StudyTime": "120001", "AccessionNumber": "12345678" } expected_meta = { 'ShamID': 'NTE3OTYH32XNES3LPNKR2U6CVOCZXDIL', 'ShamName': 'NADERMAN^TRACY^E', 'ShamBirthDate': "19991009", 'ShamStudyDateTime': datetime.datetime(2017, 10, 10, 12, 15, 3) } d = ShamDixel(tags=tags) logging.debug(d) assert (expected_meta.items() <= d.meta.items()) assert (d.meta["ShamName"] == "NADERMAN^TRACY^E") assert (d.ShamStudyDate() == "20171010") assert ( d.meta["ShamAccessionNumber"] == "25d55ad283aa400af464c76d713c07ad") logging.debug(d.orthanc_sham_map()) expected_replacement_map = \ {'Replace': {'PatientName': 'NADERMAN^TRACY^E', 'PatientID': 'NTE3OTYH32XNES3LPNKR2U6CVOCZXDIL', 'PatientBirthDate': '19991009', 'AccessionNumber': '25d55ad283aa400af464c76d713c07ad', 'StudyInstanceUID': '1.2.826.0.1.3680043.10.43.62.716180617702.336145899646', 'StudyDate': '20171010', 'StudyTime': '121503'}, 'Keep': ['PatientSex', 'StudyDescription'], 'Force': True} assert (d.orthanc_sham_map() == expected_replacement_map) c = Dixel(tags=tags) e = ShamDixel.from_dixel(c) assert (d.meta["ShamName"] == e.meta["ShamName"]) f = ShamDixel.from_dixel(c, salt="FOO") logging.debug(f.meta["ShamName"]) assert (d.meta["ShamName"] != f.meta["ShamName"])
def pull_and_save(self, items: Iterable, source: Orthanc, domain: str, dest: DcmDir, anonymize=False): def mkq(d: Dixel): return {"StudyInstanceUID": d.tags["StudyInstanceUID"]} for d in items: working_level = DicomLevel.STUDIES if anonymize: if working_level == DicomLevel.SERIES: d_fn = "{}-{}.zip".format( d.meta["ShamAccessionNumber"][0:6], d.meta["ShamSeriesDescription"]) else: d_fn = "{}.zip".format(d.meta["ShamAccessionNumber"][0:16]) else: if working_level == DicomLevel.SERIES: d_fn = "{}-{}-{}.zip".format( d.tags["PatientName"][0:6], d.tags["AccessionNumber"][0:8], d.tags["SeriesDescription"]) else: d_fn = "{}-{}.zip".format(d.tags["PatientName"][0:6], d.tags["AccessionNumber"][0:8]) if dest.exists(d_fn): logging.debug("SKIPPING {}".format(d.tags["PatientName"])) continue if not source.exists(d): source.rfind(mkq(d), domain, level=working_level, retrieve=True) else: logging.debug("SKIPPING PULL for {}".format( d.tags["PatientName"])) if anonymize: try: replacement_map = ShamDixel.orthanc_sham_map(d) anon_id = source.anonymize(d, replacement_map=replacement_map) e = source.get(anon_id, level=working_level, view=DixelView.FILE) e.meta["FileName"] = d_fn logging.debug(e) dest.put(e) source.delete(e) except (HTTPError, GatewayConnectionError) as e: logging.error("Failed to anonymize dixel") logging.error(e) with open("errors.txt", "a+") as f: f.write(d.tags["AccessionNumber"] + "\n") else: d = source.get(d, level=working_level, view=DixelView.FILE) dest.put(d) try: source.delete(d) except GatewayConnectionError as e: logging.error("Failed to delete dixel") logging.error(e)
def test_dt_shams_at_levels(): tags = { "PatientName": "FOOABC^BAR^Z", "PatientBirthDate": "20000101", "StudyDate": "20180102", "StudyTime": "120001", "AccessionNumber": "12345678" } expected_meta = { 'ShamAccessionNumber': '25d55ad283aa400af464c76d713c07ad', 'ShamBirthDate': '19991009', 'ShamID': 'NTE3OTYH32XNES3LPNKR2U6CVOCZXDIL', 'ShamName': 'NADERMAN^TRACY^E', 'StudyDateTime': datetime.datetime(2018, 1, 2, 12, 0, 1), 'ShamStudyDateTime': datetime.datetime(2017, 10, 10, 12, 15, 3) } d = ShamDixel(tags=tags, level=DicomLevel.STUDIES) logging.debug(pformat(d.meta)) assert (expected_meta.items() <= d.meta.items()) # check for imputing missing series dt tags d = ShamDixel(tags=tags, level=DicomLevel.SERIES) logging.debug(pformat(d.meta)) assert d.meta["ShamStudyDateTime"] == d.meta["ShamSeriesDateTime"] # check for imputing missing instance dt tags d = ShamDixel(tags=tags, level=DicomLevel.INSTANCES) logging.debug(pformat(d.meta)) assert d.meta["ShamInstanceCreationDateTime"] == d.meta[ "ShamSeriesDateTime"] == d.meta["ShamStudyDateTime"] tags.update({"SeriesDate": "20180102", "SeriesTime": "120101"}) expected_meta.update({ 'SeriesDateTime': datetime.datetime(2018, 1, 2, 12, 1, 1), 'ShamSeriesDateTime': datetime.datetime(2017, 10, 10, 12, 16, 3) }) d = ShamDixel(tags=tags, level=DicomLevel.SERIES) logging.debug(pformat(d.meta)) assert (expected_meta.items() <= d.meta.items()) tags.update({ "InstanceCreationDate": "20180102", "InstanceCreationTime": "120101" }) expected_meta.update({ 'InstanceCreationDateTime': datetime.datetime(2018, 1, 2, 12, 1, 1), 'ShamInstanceCreationDateTime': datetime.datetime(2017, 10, 10, 12, 16, 3) }) d = ShamDixel(tags=tags, level=DicomLevel.INSTANCES) logging.debug(pformat(d.meta)) assert (expected_meta.items() <= d.meta.items())
import logging from diana.dixel import ShamDixel from diana.apis import get_service services_path = "my_services.yml" oid = "802d6dcb-baf06419-375e594c-yyyyyyyy-xxxxxxxx" logging.basicConfig(level=logging.DEBUG) source = get_service(services_path, "internal", True) dest = get_service(services_path, "external", True) # q = { # "PatientName": patient_name # } # # result = source.find(q) # for oid in result: d = source.get(oid) dd = ShamDixel.from_dixel(d) map = ShamDixel.orthanc_sham_map(dd) e = source.anonymize(d, replacement_map=map) source.psend(e, dest) source.delete(e)