def load_templates(): vmat_example = pydicom.read_file(str( TEMPLATE_DIR.joinpath("vmat_example.dcm")), force=True) fff_example = pydicom.read_file(str( TEMPLATE_DIR.joinpath("FFF_example.dcm")), force=True) collimation = pydicom.read_file(str( TEMPLATE_DIR.joinpath("24mm_x_20mm_rectangle.dcm")), force=True) return vmat_example, fff_example, collimation
def get_dcm_ct_from_uid(ct_uid): ct_path = ct_image_paths[ct_uid] dcm_ct = pydicom.read_file(ct_path, force=True) dcm_ct.file_meta.TransferSyntaxUID = pydicom.uid.ImplicitVRLittleEndian return dcm_ct
def get_dcm_structure_from_uid(structure_set_uid): structure_set_path = structure_set_paths[structure_set_uid] dcm_structure = pydicom.read_file( structure_set_path, force=True, specific_tags=["ROIContourSequence", "StructureSetROISequence"], ) return dcm_structure
def adjust_RED_cli(args): adjustment_map = dict( zip(args.adjustment_map[::2], args.adjustment_map[1::2])) dicom_dataset = pydicom.read_file(args.input_file, force=True) new_dicom_dataset = adjust_rel_elec_density( dicom_dataset, adjustment_map, ignore_missing_structure=args.ignore_missing_structure, ) pydicom.write_file(args.output_file, new_dicom_dataset)
def merge_contours_cli(args): dicom_dataset = pydicom.read_file(args.input_file, force=True) if args.structures is None: for roi_contour_sequence in dicom_dataset.ROIContourSequence: merge_contours(roi_contour_sequence, inplace=True) else: for structure in args.structures: roi_contour_sequence = get_roi_contour_sequence_by_name( structure, dicom_dataset) merge_contours(roi_contour_sequence, inplace=True) pydicom.write_file(args.output_file, dicom_dataset)
def get_structure_names_by_uids(structure_set_paths, names_map): structure_names_by_ct_uid = {} structure_names_by_structure_set_uid = {} for structure_set_uid, structure_set_path in structure_set_paths.items(): structure_set = pydicom.read_file( structure_set_path, force=True, specific_tags=["ROIContourSequence", "StructureSetROISequence"], ) number_to_name_map = { roi_sequence_item.ROINumber: names_map[roi_sequence_item.ROIName] for roi_sequence_item in structure_set.StructureSetROISequence if names_map[roi_sequence_item.ROIName] is not None } structure_names_by_structure_set_uid[structure_set_uid] = [ item for _, item in number_to_name_map.items() ] for roi_contour_sequence_item in structure_set.ROIContourSequence: try: structure_name = number_to_name_map[ roi_contour_sequence_item.ReferencedROINumber] except KeyError: continue for contour_sequence_item in roi_contour_sequence_item.ContourSequence: contour_imaging_sequence = contour_sequence_item.ContourImageSequence ct_uid = contour_imaging_sequence[0].ReferencedSOPInstanceUID try: structure_names_by_ct_uid[ct_uid].add(structure_name) except KeyError: structure_names_by_ct_uid[ct_uid] = set([structure_name]) structure_names_by_ct_uid = { key: list(item) for key, item in structure_names_by_ct_uid.items() } return structure_names_by_ct_uid, structure_names_by_structure_set_uid
def dicom_input_method( # pylint: disable = too-many-return-statements key_namespace="", patient_id="", **_): FILE_UPLOAD = "File upload" MONACO_SEARCH = "Search Monaco file export location" dicom_export_locations = get_dicom_export_locations() import_method = st.radio( "DICOM import method", [FILE_UPLOAD, MONACO_SEARCH], key=f"{key_namespace}_dicom_file_import_method", ) if import_method == FILE_UPLOAD: dicom_plan_bytes = st.file_uploader( "Upload DICOM RT Plan File", key=f"{key_namespace}_dicom_plan_uploader") if dicom_plan_bytes is None: return {} try: dicom_plan = pydicom.read_file(dicom_plan_bytes, force=True) except: # pylint: disable = bare-except st.write(WrongFileType("Does not appear to be a DICOM file")) return {} if dicom_plan.SOPClassUID != DICOM_PLAN_UID: st.write( WrongFileType( "The DICOM type needs to be an RT DICOM Plan file")) return {} data_paths = ["Uploaded DICOM file"] if import_method == MONACO_SEARCH: site_options = list(dicom_export_locations.keys()) monaco_site = st.radio("Monaco Export Location", site_options, key=f"{key_namespace}_monaco_site") monaco_export_directory = dicom_export_locations[monaco_site] st.write(monaco_export_directory.resolve()) patient_id = st.text_input("Patient ID", patient_id, key=f"{key_namespace}_patient_id") found_dicom_files = list( monaco_export_directory.glob(f"{patient_id}_*.dcm")) dicom_plans = {} for path in found_dicom_files: dcm = load_dicom_file_if_plan(path) if dcm is not None: dicom_plans[path.name] = dcm dicom_plan_options = list(dicom_plans.keys()) if len(dicom_plan_options) == 0 and patient_id != "": st.write( NoRecordsFound( f"No exported DICOM RT plans found for Patient ID {patient_id} " f"within the directory {monaco_export_directory}")) return {"patient_id": patient_id} if len(dicom_plan_options) == 1: selected_plan = dicom_plan_options[0] else: selected_plan = st.radio( "Select DICOM Plan", dicom_plan_options, key=f"{key_namespace}_select_monaco_export_plan", ) f"DICOM file being used: `{selected_plan}`" dicom_plan = dicom_plans[selected_plan] data_paths = [monaco_export_directory.joinpath(selected_plan)] patient_id = str(dicom_plan.PatientID) f"Patient ID: `{patient_id}`" patient_name = str(dicom_plan.PatientName) patient_name = utl_patient.convert_patient_name(patient_name) f"Patient Name: `{patient_name}`" rt_plan_name = str(dicom_plan.RTPlanName) f"Plan Name: `{rt_plan_name}`" try: deliveries_all_fractions = pymedphys.Delivery.from_dicom( dicom_plan, fraction_number="all") except AttributeError: st.write(WrongFileType("Does not appear to be a photon DICOM plan")) return {} fractions = list(deliveries_all_fractions.keys()) if len(fractions) == 1: delivery = deliveries_all_fractions[fractions[0]] else: fraction_choices = {} for fraction, delivery in deliveries_all_fractions.items(): rounded_mu = round(delivery.mu[-1], 1) fraction_choices[ f"Perscription {fraction} with {rounded_mu} MU"] = fraction fraction_selection = st.radio( "Select relevant perscription", list(fraction_choices.keys()), key=f"{key_namespace}_dicom_perscription_chooser", ) fraction_number = fraction_choices[fraction_selection] delivery = deliveries_all_fractions[fraction_number] deliveries = [delivery] identifier = f"DICOM ({rt_plan_name})" return { "patient_id": patient_id, "patient_name": patient_name, "data_paths": data_paths, "identifier": identifier, "deliveries": deliveries, }
def load_dicom_file_if_plan(filepath): dcm = pydicom.read_file(str(filepath), force=True, stop_before_pixels=True) if dcm.SOPClassUID == DICOM_PLAN_UID: return dcm return None
def convert_image(image, export_path): patient_info = image.pinnacle.patient_info image_info = image.image_info image.logger.debug( "Converting image patient name, birthdate and id to match pinnacle\n") dicom_directory = os.path.join( image.path, "ImageSet_%s.DICOM" % str(image.image["ImageSetID"])) if not os.path.exists(dicom_directory): # Image set folder not found, need to ignore patient # Will want to call a function to be written that will create image set # files from the condensed pixel data file image.logger.info( "Dicom Image files do not exist. Creating image files") create_image_files(image, export_path) return for file in os.listdir(dicom_directory): # try: imageds = pydicom.read_file(os.path.join(dicom_directory, file), force=True) imageds.PatientName = image.pinnacle.patient_info["FullName"] imageds.PatientID = image.pinnacle.patient_info["MedicalRecordNumber"] imageds.PatientBirthDate = image.pinnacle.patient_info["DOB"] # Really need to rewrite file meta? This can cause errors with different # TransferSyntaxUIDs... # try: # file_meta = Dataset() # file_meta.TransferSyntaxUID = GTransferSyntaxUID # file_meta.MediaStorageSOPClassUID = '1.2.840.10008.5.1.4.1.1.2' # file_meta.MediaStorageSOPInstanceUID = imageds.SOPInstanceUID # file_meta.ImplementationClassUID = GImplementationClassUID # imageds.file_meta = file_meta # except: # image.logger.warn('Unable to process image: ' + file) # continue # # if not "SOPClassUID" in imageds: # # No SOP Class UID set, read it from the image info # imageds = image_info[0]['ClassUID'] if not "SOPInstanceUID" in imageds: image.logger.warn("Unable to process image: " + file) continue file_meta = imageds.file_meta preamble = getattr(imageds, "preamble", None) if not preamble: preamble = b"\x00" * 128 output_file = os.path.join( export_path, "%s.%s.dcm" % (image.image["Modality"], imageds.SOPInstanceUID)) currfile = pydicom.dataset.FileDataset(output_file, {}, file_meta=file_meta, preamble=preamble) imageds.save_as(output_file) image.logger.info("Exported: " + file + " to " + output_file)
def get_uid_cache(data_path_root, validate_cache=True): """Get inter-relationship maps between dicom files. Dicom files are to be placed within ``data_path_root/dicom``. A cache will be created at ``data_path_root/mappings/uid-cache.json``. Any change of the file structure within data_path_root/dicom will cause the cache to be flushed. """ data_path_root = pathlib.Path(data_path_root) uid_cache_path = data_path_root.joinpath("mappings", "uid-cache.json") dcm_paths = list(data_path_root.rglob("dicom/**/*.dcm")) relative_paths = [ str(path.relative_to(data_path_root)) for path in dcm_paths ] try: with open(uid_cache_path) as f: uid_cache = json.load(f) except (FileNotFoundError, json.JSONDecodeError): uid_cache = { "ct_image_paths": {}, "structure_set_paths": {}, "ct_uid_to_structure_uid": {}, "paths_when_run": [], } if validate_cache and set( uid_cache["paths_when_run"]) != set(relative_paths): dcm_headers = [] for dcm_path in dcm_paths: dcm_headers.append( pydicom.read_file( dcm_path, force=True, specific_tags=[ "SOPInstanceUID", "SOPClassUID", "StudyInstanceUID" ], )) ct_image_paths = { str(header.SOPInstanceUID): str(path) for header, path in zip(dcm_headers, relative_paths) if header.SOPClassUID.name == "CT Image Storage" } structure_set_paths = { str(header.SOPInstanceUID): str(path) for header, path in zip(dcm_headers, relative_paths) if header.SOPClassUID.name == "RT Structure Set Storage" } ct_uid_to_study_instance_uid = { str(header.SOPInstanceUID): str(header.StudyInstanceUID) for header in dcm_headers if header.SOPClassUID.name == "CT Image Storage" } study_instance_uid_to_structure_uid = { str(header.StudyInstanceUID): str(header.SOPInstanceUID) for header in dcm_headers if header.SOPClassUID.name == "RT Structure Set Storage" } ct_uid_to_structure_uid = { ct_uid: study_instance_uid_to_structure_uid[study_uid] for ct_uid, study_uid in ct_uid_to_study_instance_uid.items() } uid_cache["ct_image_paths"] = ct_image_paths uid_cache["structure_set_paths"] = structure_set_paths uid_cache["ct_uid_to_structure_uid"] = ct_uid_to_structure_uid uid_cache["paths_when_run"] = relative_paths with open(uid_cache_path, "w") as f: json.dump(uid_cache, f) return read_uid_cache(data_path_root, uid_cache)
def adjust_machine_name_cli(args): dicom_dataset = pydicom.read_file(args.input_file, force=True) new_dicom_dataset = adjust_machine_name(dicom_dataset, args.new_machine_name) pydicom.write_file(args.output_file, new_dicom_dataset)
def adjust_RED_by_structure_name_cli(args): dicom_dataset = pydicom.read_file(args.input_file, force=True) new_dicom_dataset = adjust_RED_by_structure_name(dicom_dataset) pydicom.write_file(args.output_file, new_dicom_dataset)