Пример #1
0
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
Пример #2
0
    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
Пример #3
0
    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
Пример #4
0
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)
Пример #5
0
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)
Пример #6
0
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
Пример #7
0
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,
    }
Пример #8
0
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
Пример #9
0
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)
Пример #10
0
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)
Пример #11
0
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)
Пример #12
0
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)