Exemplo n.º 1
0
def register_images(image_1, image_2):
    """
    Registers the moving and fixed image.
    Args:
        image_1 (Image Matrix)
        image_2 (Image Matrix)
    Return:
        img_ct (Array)
        tfm (sitk.CompositeTransform)
    """

    store_object_into_dcm = False

    # Check to see if the imageWindowing.csv file exists
    if os.path.exists(data_path('imageFusion.json')):
        # If it exists, read data from file into the dictionary
        with open(data_path("imageFusion.json"), "r") as file_input:
            dict_fusion = json.load(file_input)

        img_ct, tfm = linear_registration(
            image_1,
            image_2,
            reg_method=dict_fusion["reg_method"],
            metric=dict_fusion["metric"],
            optimiser=dict_fusion["optimiser"],
            shrink_factors=dict_fusion["shrink_factors"],
            smooth_sigmas=dict_fusion["smooth_sigmas"],
            sampling_rate=dict_fusion["sampling_rate"],
            final_interp=dict_fusion["final_interp"],
            number_of_iterations=dict_fusion["number_of_iterations"],
            default_value=dict_fusion["default_value"],
            verbose=False)

        # Flag for when a given registration method is rigid.
        # As DICOM Frame of Reference Transformation Matrix allows
        # RIGID, RIGID_SCALE or AFFINE

        if dict_fusion["reg_method"] == 'rigid':
            store_object_into_dcm = True
    else:
        # If csv does not exist, initialize registration normally
        img_ct, tfm = linear_registration(image_1,
                                          image_2,
                                          shrink_factors=[8],
                                          smooth_sigmas=[10],
                                          reg_method='rigid',
                                          verbose=False)
        store_object_into_dcm = True

    return img_ct, tfm, store_object_into_dcm
    def find_roi_names(self):
        """
        Return a list of ROI names in the RTSS that are standard organ names.
        :return: list of ROI names.
        """
        # Get organ names and FMA IDs if they have not been populated
        if not self.organ_names:
            # Get standard organ names
            with open(data_path('organName.csv'), 'r') as f:
                csv_input = csv.reader(f)
                header = next(f)  # Ignore the "header" of the column
                for row in csv_input:
                    self.organ_names.append(row[0])
                    self.fma_ids[row[0]] = row[1]
                f.close()

        rtss = self.patient_dict_container.dataset['rtss']
        rois = []
        # Loop through each ROI in the RT Struct
        for i in range(len(rtss.StructureSetROISequence)):
            # Get the ROI name
            roi_name = rtss.StructureSetROISequence[i].ROIName

            # Add ROI name to the list
            if roi_name in self.organ_names:
                rois.append(roi_name)

        return rois
Exemplo n.º 3
0
 def draw_roi_polygons(self, roi_id, polygons, roi_color=None):
     """
     Draw ROI polygons on the image slice
     :param roi_id: ROI number
     :param polygons: List of ROI polygons
     :param roi_color: colors for ROIs used when displaying selected rois in
     manipulate ROI window
     """
     if roi_color is None:
         color = self.roi_color[roi_id]
     else:
         color = roi_color[roi_id]
     with open(data_path('line&fill_configuration'), 'r') as stream:
         elements = stream.readlines()
         if len(elements) > 0:
             roi_line = int(elements[0].replace('\n', ''))
             roi_opacity = int(elements[1].replace('\n', ''))
             line_width = float(elements[4].replace('\n', ''))
         else:
             roi_line = 1
             roi_opacity = 10
             line_width = 2.0
         stream.close()
     roi_opacity = int((roi_opacity / 100) * 255)
     color.setAlpha(roi_opacity)
     pen_color = QtGui.QColor(color.red(), color.green(), color.blue())
     pen = self.get_qpen(pen_color, roi_line, line_width)
     for i in range(len(polygons)):
         self.scene.addPolygon(polygons[i], pen, QtGui.QBrush(color))
Exemplo n.º 4
0
    def init_standard_names(self):
        """
        Create two lists containing standard organ and standard volume names
        as set by the Add-On options.
        """
        with open(data_path('organName.csv'), 'r') as f:
            self.standard_organ_names = []

            csv_input = csv.reader(f)
            header = next(f)  # Ignore the "header" of the column
            for row in csv_input:
                self.standard_organ_names.append(row[0])

        with open(data_path('volumeName.csv'), 'r') as f:
            self.standard_volume_names = []

            csv_input = csv.reader(f)
            header = next(f)  # Ignore the "header" of the column
            for row in csv_input:
                self.standard_volume_names.append(row[1])
Exemplo n.º 5
0
    def get_standard_names(self):
        """
        Get standard organ names and prefix types.
        """
        # Get standard organ names
        with open(data_path('organName.csv'), 'r') as f:
            csv_input = csv.reader(f)
            header = next(f)  # Ignore the "header" of the column
            for row in csv_input:
                self.organ_names.append(row[0])
                self.organ_names_lowercase.append(row[0].lower())
            f.close()

        # Get standard volume prefixes
        with open(data_path('volumeName.csv'), 'r') as f:
            csv_input = csv.reader(f)
            header = next(f)  # Ignore the "header" of the column
            for row in csv_input:
                self.volume_prefixes.append(row[1])
            f.close()
Exemplo n.º 6
0
 def save_isodoses(self):
     """
     Called when batch conversion process starts, to save any changes
     that may have been made to the table.
     """
     with open(data_path('batch_isodoseRoi.csv'), 'w', newline="") \
             as stream:
         writer = csv.writer(stream)
         for row in range(self.table_roi.rowCount()):
             rowdata = []
             for column in range(self.table_roi.columnCount()):
                 item = self.table_roi.item(row, column)
                 if item is not None:
                     rowdata.append(item.text())
                 else:
                     rowdata.append('')
             writer.writerow(rowdata)
Exemplo n.º 7
0
    def isodose_display(self):
        """
        Display isodoses on the DICOM Image.
        """
        slider_id = self.slider.value()
        curr_slice_uid = self.patient_dict_container.get("dict_uid")[slider_id]
        z = self.patient_dict_container.dataset[
            slider_id].ImagePositionPatient[2]
        dataset_rtdose = self.patient_dict_container.dataset['rtdose']
        grid = get_dose_grid(dataset_rtdose, float(z))

        if not (grid == []):
            # sort selected_doses in ascending order so that the high dose isodose washes
            # paint over the lower dose isodose washes
            for sd in sorted(
                    self.patient_dict_container.get("selected_doses")):
                dose_level = sd * self.patient_dict_container.get("rx_dose_in_cgray") / \
                    (dataset_rtdose.DoseGridScaling * 10000)
                contours = measure.find_contours(grid, dose_level)

                polygons = self.calc_dose_polygon(
                    self.patient_dict_container.get("dose_pixluts")
                    [curr_slice_uid], contours)

                brush_color = self.iso_color[sd]
                with open(data_path('line&fill_configuration'), 'r') as stream:
                    elements = stream.readlines()
                    if len(elements) > 0:
                        iso_line = int(elements[2].replace('\n', ''))
                        iso_opacity = int(elements[3].replace('\n', ''))
                        line_width = float(elements[4].replace('\n', ''))
                    else:
                        iso_line = 2
                        iso_opacity = 5
                        line_width = 2.0
                    stream.close()
                iso_opacity = int((iso_opacity / 100) * 255)
                brush_color.setAlpha(iso_opacity)
                pen_color = QtGui.QColor(brush_color.red(),
                                         brush_color.green(),
                                         brush_color.blue())
                pen = self.get_qpen(pen_color, iso_line, line_width)
                for i in range(len(polygons)):
                    self.scene.addPolygon(polygons[i], pen,
                                          QtGui.QBrush(brush_color))
Exemplo n.º 8
0
    def start_conversion(self, interrupt_flag, progress_callback):
        """
        Goes the the steps of the iso2roi conversion.
        :param interrupt_flag: interrupt flag to stop process
        :param progress_callback: signal that receives the current
                                  progress of the loading.
        """
        progress_callback.emit(("Validating Datasets", 0))

        # Stop loading
        if interrupt_flag.is_set():
            # TODO: convert print to logging
            print("Stopped ISO2ROI")
            return False

        # Get isodose levels to turn into ROIs
        isodose_levels = self.get_iso_levels(data_path('isodoseRoi.csv'))

        # Stop loading
        if interrupt_flag.is_set():
            # TODO: convert print to logging
            print("Stopped ISO2ROI")
            return False

        # Calculate dose boundaries
        progress_callback.emit(("Calculating Boundaries", 50))
        boundaries = self.calculate_isodose_boundaries(isodose_levels)

        # Return if boundaries could not be calculated
        if not boundaries:
            # TODO: convert print to logging
            print("Boundaries could not be calculated.")
            return

        # Stop loading
        if interrupt_flag.is_set():
            # TODO: convert print to logging
            print("Stopped ISO2ROI")
            return False

        progress_callback.emit(("Generating ROIs", 75))
        self.generate_roi(boundaries, progress_callback)
        progress_callback.emit(("Reloading Window. Please Wait...", 95))
Exemplo n.º 9
0
    def start(self):
        """
        Goes through the steps of the ISO2ROI conversion.
        :return: True if successful, False if not.
        """
        # Stop loading
        if self.interrupt_flag.is_set():
            # TODO: convert print to logging
            print("Stopped ISO2ROI")
            self.patient_dict_container.clear()
            self.summary = "INTERRUPT"
            return False

        if not self.ready:
            self.summary = "SKIP"
            return False

        # Update progress
        self.progress_callback.emit(("Setting up...", 30))

        # Initialise
        InitialModel.create_initial_model_batch()

        # Stop loading
        if self.interrupt_flag.is_set():
            # TODO: convert print to logging
            print("Stopped ISO2ROI")
            self.patient_dict_container.clear()
            self.summary = "INTERRUPT"
            return False

        # Check if the dataset is complete
        self.progress_callback.emit(("Checking dataset...", 40))
        dataset_complete = ImageLoading.is_dataset_dicom_rt(
            self.patient_dict_container.dataset)

        # Create ISO2ROI object
        iso2roi = ISO2ROI()
        self.progress_callback.emit(("Performing ISO2ROI... ", 50))

        # Stop loading
        if self.interrupt_flag.is_set():
            # TODO: convert print to logging
            print("Stopped ISO2ROI")
            self.patient_dict_container.clear()
            self.summary = "INTERRUPT"
            return False

        if not dataset_complete:
            # Check if RT struct file is missing. If yes, create one and
            # add its data to the patient dict container. Otherwise
            # return
            if not self.patient_dict_container.get("file_rtss"):
                self.progress_callback.emit(("Generating RT Struct", 55))
                self.create_new_rtstruct(self.progress_callback)

        # Get isodose levels to turn into ROIs
        isodose_levels = \
            iso2roi.get_iso_levels(data_path('batch_isodoseRoi.csv'))

        # Stop loading
        if self.interrupt_flag.is_set():
            # TODO: convert print to logging
            print("Stopped ISO2ROI")
            self.patient_dict_container.clear()
            self.summary = "INTERRUPT"
            return False

        # Calculate boundaries
        self.progress_callback.emit(("Calculating boundaries...", 60))
        boundaries = iso2roi.calculate_isodose_boundaries(isodose_levels)

        # Return if boundaries could not be calculated
        if not boundaries:
            print("Boundaries could not be calculated.")
            self.summary = "ISO_NO_RX_DOSE"
            return False

        # Generate ROIs
        self.progress_callback.emit(("Generating ROIs...", 80))
        iso2roi.generate_roi(boundaries, self.progress_callback)

        # Save new RTSS
        self.progress_callback.emit(("Saving RT Struct...", 90))
        self.save_rtss()
        return True
Exemplo n.º 10
0
def create_initial_model_batch():
    """
    This function initializes all the attributes in the PatientDictContainer
    required for the operation of batch processing. It is a modified version
    of create_initial_model. This function only sets RTSS values in the
    PatientDictContainer if an RTSS exists. If one does not exist it will only
    be created if needed, whereas the original create_initial_model assumes
    that one is always created. This function also does not set SR attributes
    in the PatientDictContainer, as SRs are only needed for SR2CSV functions,
    which do not require the use of the PatientDictContainer.
    """
    ##############################
    #  LOAD PATIENT INFORMATION  #
    ##############################
    patient_dict_container = PatientDictContainer()

    dataset = patient_dict_container.dataset
    filepaths = patient_dict_container.filepaths
    patient_dict_container.set("rtss_modified", False)

    if 'WindowWidth' in dataset[0]:
        if isinstance(dataset[0].WindowWidth, pydicom.valuerep.DSfloat):
            window = int(dataset[0].WindowWidth)
        elif isinstance(dataset[0].WindowWidth, pydicom.multival.MultiValue):
            window = int(dataset[0].WindowWidth[1])
    else:
        window = int(400)

    if 'WindowCenter' in dataset[0]:
        if isinstance(dataset[0].WindowCenter, pydicom.valuerep.DSfloat):
            level = int(dataset[0].WindowCenter)
        elif isinstance(dataset[0].WindowCenter, pydicom.multival.MultiValue):
            level = int(dataset[0].WindowCenter[1])
    else:
        level = int(800)

    patient_dict_container.set("window", window)
    patient_dict_container.set("level", level)

    # Check to see if the imageWindowing.csv file exists
    if os.path.exists(data_path('imageWindowing.csv')):
        # If it exists, read data from file into the self.dict_windowing
        # variable
        dict_windowing = {}
        with open(data_path('imageWindowing.csv'), "r") \
                as fileInput:
            next(fileInput)
            dict_windowing["Normal"] = [window, level]
            for row in fileInput:
                # Format: Organ - Scan - Window - Level
                items = [item for item in row.split(',')]
                dict_windowing[items[0]] = [int(items[2]), int(items[3])]
    else:
        # If csv does not exist, initialize dictionary with default values
        dict_windowing = {
            "Normal": [window, level],
            "Lung": [1600, -300],
            "Bone": [1400, 700],
            "Brain": [160, 950],
            "Soft Tissue": [400, 800],
            "Head and Neck": [275, 900]
        }

    patient_dict_container.set("dict_windowing", dict_windowing)

    pixel_values = convert_raw_data(dataset)
    # Calculate the ratio between x axis and y axis of 3 views
    pixmap_aspect = {}
    pixel_spacing = dataset[0].PixelSpacing
    slice_thickness = dataset[0].SliceThickness
    pixmap_aspect["axial"] = pixel_spacing[1] / pixel_spacing[0]
    pixmap_aspect["sagittal"] = pixel_spacing[1] / slice_thickness
    pixmap_aspect["coronal"] = slice_thickness / pixel_spacing[0]
    pixmaps_axial, pixmaps_coronal, pixmaps_sagittal = \
        get_pixmaps(pixel_values, window, level, pixmap_aspect)

    patient_dict_container.set("pixmaps_axial", pixmaps_axial)
    patient_dict_container.set("pixmaps_coronal", pixmaps_coronal)
    patient_dict_container.set("pixmaps_sagittal", pixmaps_sagittal)
    patient_dict_container.set("pixel_values", pixel_values)
    patient_dict_container.set("pixmap_aspect", pixmap_aspect)

    basic_info = get_basic_info(dataset[0])
    patient_dict_container.set("basic_info", basic_info)

    patient_dict_container.set("dict_uid", dict_instance_uid(dataset))

    # Set RTSS attributes
    if patient_dict_container.has_modality("rtss"):
        patient_dict_container.set("file_rtss", filepaths['rtss'])
        patient_dict_container.set("dataset_rtss", dataset['rtss'])
        dict_raw_contour_data, dict_numpoints = \
            ImageLoading.get_raw_contour_data(dataset['rtss'])
        patient_dict_container.set("raw_contour", dict_raw_contour_data)
        dicom_tree_rtss = DicomTree(filepaths['rtss'])
        patient_dict_container.set("dict_dicom_tree_rtss",
                                   dicom_tree_rtss.dict)

        patient_dict_container.set(
            "list_roi_numbers",
            ordered_list_rois(patient_dict_container.get("rois")))
        patient_dict_container.set("selected_rois", [])

        patient_dict_container.set("dict_polygons_axial", {})
        patient_dict_container.set("dict_polygons_sagittal", {})
        patient_dict_container.set("dict_polygons_coronal", {})

    # Set RTDOSE attributes
    if patient_dict_container.has_modality("rtdose"):
        dicom_tree_rtdose = DicomTree(filepaths['rtdose'])
        patient_dict_container.set("dict_dicom_tree_rtdose",
                                   dicom_tree_rtdose.dict)

        patient_dict_container.set("dose_pixluts", get_dose_pixluts(dataset))

        patient_dict_container.set("selected_doses", [])

        # overwritten if RTPLAN is present.
        patient_dict_container.set("rx_dose_in_cgray", 1)

    # Set RTPLAN attributes
    if patient_dict_container.has_modality("rtplan"):
        # the TargetPrescriptionDose is type 3 (optional), so it may not be
        # there However, it is preferable to the sum of the beam doses
        # DoseReferenceStructureType is type 1 (value is mandatory), but it
        # can have a value of ORGAN_AT_RISK rather than TARGET in which case
        # there will *not* be a TargetPrescriptionDose and even if it is
        # TARGET, that's no guarantee that TargetPrescriptionDose will be
        # encoded and have a value
        rx_dose_in_cgray = calculate_rx_dose_in_cgray(dataset["rtplan"])
        patient_dict_container.set("rx_dose_in_cgray", rx_dose_in_cgray)

        dicom_tree_rtplan = DicomTree(filepaths['rtplan'])
        patient_dict_container.set("dict_dicom_tree_rtplan",
                                   dicom_tree_rtplan.dict)
Exemplo n.º 11
0
    def create_table_view(self):
        """
        Create a table to hold all the isodose levels for ISO2ROI.
        """
        # Create table
        self.table_roi = QtWidgets.QTableWidget(self)
        self.table_roi.setStyleSheet("background-color: rgb(255, 255, 255);")
        self.table_roi.setColumnCount(4)
        self.table_roi.verticalHeader().hide()
        self.table_roi.setHorizontalHeaderLabels(
            [" Isodose Level ", " Unit ", " ROI Name ", " Notes "])

        self.table_roi.horizontalHeaderItem(0).setTextAlignment(
            QtCore.Qt.AlignLeft)
        self.table_roi.horizontalHeaderItem(1).setTextAlignment(
            QtCore.Qt.AlignLeft)
        self.table_roi.horizontalHeaderItem(2).setTextAlignment(
            QtCore.Qt.AlignLeft)
        self.table_roi.horizontalHeaderItem(3).setTextAlignment(
            QtCore.Qt.AlignLeft)

        roi_from_isodose_header = self.table_roi.horizontalHeader()
        roi_from_isodose_header.setSectionResizeMode(
            0, QtWidgets.QHeaderView.Stretch)
        roi_from_isodose_header.setSectionResizeMode(
            1, QtWidgets.QHeaderView.Stretch)
        roi_from_isodose_header.setSectionResizeMode(
            2, QtWidgets.QHeaderView.Stretch)
        roi_from_isodose_header.setSectionResizeMode(
            3, QtWidgets.QHeaderView.Stretch)

        # Removing the ability to edit tables with immediate click
        self.table_roi.setEditTriggers(QtWidgets.QTreeView.NoEditTriggers
                                       | QtWidgets.QTreeView.NoEditTriggers)

        # Add table to the main layout
        self.main_layout.addWidget(self.table_roi)

        # Add right click options
        self.table_roi.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.table_roi.customContextMenuRequested.connect(
            self.on_custom_context_menu_requested_roi)

        # Populate the table with data from batch_isodoseRoi.csv
        with open(data_path('batch_isodoseRoi.csv'), "r") as fileInput:
            # Clear table to prevent displaying data multiple times
            self.table_roi.setRowCount(0)

            # Loop through each row
            for i, row in enumerate(fileInput):
                items = [
                    QtWidgets.QTableWidgetItem(str(item.replace('\n', '')))
                    for item in row.split(',')
                ]

                # Add row to table
                self.table_roi.insertRow(i)
                self.table_roi.setItem(i, 0, items[0])
                self.table_roi.setItem(i, 1, items[1])
                self.table_roi.setItem(i, 2, items[2])
                if len(items) > 3:
                    self.table_roi.setItem(i, 3, items[3])
Exemplo n.º 12
0
    def fill_tables(self):
        # Fill the Windowing table
        with open(data_path("imageWindowing.csv"), "r") as file_input:
            next(file_input)
            i = 0
            for row in file_input:
                items = [
                    QTableWidgetItem(str(item.replace("\n", "")))
                    for item in row.split(",")
                ]
                if i >= self.table_view.rowCount():
                    self.table_view.setRowCount(self.table_view.rowCount() + 1)
                self.table_view.setItem(i, 0, items[0])
                self.table_view.setItem(i, 1, items[1])
                self.table_view.setItem(i, 2, items[2])
                self.table_view.setItem(i, 3, items[3])
                i += 1

        # organ names table
        with open(data_path("organName.csv"), "r") as file_input:
            next(file_input)
            i = 0
            for row in file_input:
                items = [
                    QTableWidgetItem(str(item.replace("\n", "")))
                    for item in row.split(",")
                ]
                if i >= self.table_organ.rowCount():
                    self.table_organ.setRowCount(self.table_organ.rowCount() +
                                                 1)
                self.table_organ.setItem(i, 0, items[0])
                self.table_organ.setItem(i, 1, items[1])
                self.table_organ.setItem(i, 2, items[2])
                if len(items) > 3:
                    self.table_organ.setItem(i, 3, items[3])
                i += 1

        # volume name table
        with open(data_path("volumeName.csv"), "r") as file_input:
            i = 0
            for row in file_input:
                items = [
                    QTableWidgetItem(str(item.replace("\n", "")))
                    for item in row.split(",")
                ]
                if i >= self.table_volume.rowCount():
                    self.table_volume.setRowCount(
                        self.table_volume.rowCount() + 1)
                self.table_volume.setItem(i, 0, items[0])
                self.table_volume.setItem(i, 1, items[1])
                i += 1

        # roi isodose table
        with open(data_path('isodoseRoi.csv'), "r") as fileInput:
            # Clear table to prevent displaying data multiple times
            self.table_roi.setRowCount(0)

            # Loop through each row
            for i, row in enumerate(fileInput):
                items = [
                    QTableWidgetItem(str(item.replace('\n', '')))
                    for item in row.split(',')
                ]

                # Add row to table
                self.table_roi.insertRow(i)
                self.table_roi.setItem(i, 0, items[0])
                self.table_roi.setItem(i, 1, items[1])
                self.table_roi.setItem(i, 2, items[2])
                if len(items) > 3:
                    self.table_roi.setItem(i, 3, items[3])

        # patient hash ID table, which is just for displaying all the
        # patients anonymized byt the software since intallation
        with open(data_path("patientHash.csv"), "r") as file_input:
            next(file_input, None)
            i = 0
            for row in file_input:
                items = [
                    QTableWidgetItem(str(item.replace("\n", "")))
                    for item in row.split(",")
                ]
                if len(items) >= 2:
                    if i >= self.table_ids.rowCount():
                        self.table_ids.setRowCount(self.table_ids.rowCount() +
                                                   1)
                    self.table_ids.setItem(i, 0, items[0])
                    self.table_ids.setItem(i, 1, items[1])
                i += 1

        # Image Fusion
        try:
            with open(data_path("imageFusion.json"), "r") as file_input:
                data = json.load(file_input)
                for key in data:
                    self.image_fusion_add_on_options.set_value(key, data[key])
            self.image_fusion_add_on_options.set_gridLayout()
        except FileNotFoundError:
            self.image_fusion_add_on_options.set_fast_mode()
            QMessageBox.critical(
                self, "File Not Found!",
                "Could not find imageFusion.json file for\nimage fusion "
                "add-ons.")
Exemplo n.º 13
0
    def accepting(self):
        """
        If APPLY is clicked, save the contents of each option and table
        into their corresponding files.
        """
        save_flag = True

        # starting save
        # Saving the Windowing options
        with open(data_path("imageWindowing.csv"), "w", newline="") as stream:
            writer = csv.writer(stream)
            writer.writerow(["Organ", "Scan", "Window", "Level"])
            for row in range(self.table_view.rowCount()):
                rowdata = []
                for column in range(self.table_view.columnCount()):
                    item = self.table_view.item(row, column)
                    if item is not None:
                        rowdata.append(item.text())
                    else:
                        rowdata.append("")
                writer.writerow(rowdata)
        # saving the Standard Organ names
        with open(data_path("organName.csv"), "w", newline="") as stream:
            writer = csv.writer(stream)
            writer.writerow(["Standard Name", "FMA ID", "Organ", "Url"])
            for row in range(self.table_organ.rowCount()):
                rowdata = []
                for column in range(self.table_organ.columnCount()):
                    item = self.table_organ.item(row, column)
                    if item is not None:
                        rowdata.append(item.text())
                    else:
                        rowdata.append("")
                writer.writerow(rowdata)
        # Saving the Standard Volume Names
        with open(data_path("volumeName.csv"), "w", newline="") as stream:
            writer = csv.writer(stream)
            for row in range(self.table_volume.rowCount()):
                rowdata = []
                for column in range(self.table_volume.columnCount()):
                    item = self.table_volume.item(row, column)
                    if item is not None:
                        rowdata.append(item.text())
                    else:
                        rowdata.append("")
                writer.writerow(rowdata)

        # saves the new ROI from Isodoses
        with open(data_path('isodoseRoi.csv'), 'w', newline="") as stream:
            writer = csv.writer(stream)
            for row in range(self.table_roi.rowCount()):
                rowdata = []
                for column in range(self.table_roi.columnCount()):
                    item = self.table_roi.item(row, column)
                    if item is not None:
                        rowdata.append(item.text())
                    else:
                        rowdata.append('')
                writer.writerow(rowdata)

        # save configuration file
        with open(data_path("line&fill_configuration"), "w") as stream:
            stream.write(str(self.line_style_ROI.currentIndex()))
            stream.write("\n")
            stream.write(str(self.opacity_ROI.value()))
            stream.write("\n")
            stream.write(str(self.line_style_ISO.currentIndex()))
            stream.write("\n")
            stream.write(str(self.opacity_ISO.value()))
            stream.write("\n")
            stream.write(str(self.line_width.currentText()))
            stream.write("\n")
            stream.close()

        # Save the default directory and clinical data CSV directory
        configuration = Configuration()
        try:
            new_dir = self.change_default_directory. \
                change_default_directory_input_box.text()
            configuration.update_default_directory(new_dir)
            new_clinical_data_csv_dir = \
                self.clinical_data_csv_dir_options. \
                    clinical_data_csv_dir_input_box.text()
            configuration.update_clinical_data_csv_dir(
                new_clinical_data_csv_dir)
        except SqlError:
            configuration.set_up_config_db()
            QMessageBox.critical(
                self, "Config file error",
                "Failed to update default directory.\nPlease try again.")
            save_flag = False

        # Image Fusion
        try:
            image_fusion_add_on_options_values = \
                self.image_fusion_add_on_options.get_values_from_UI()
            self.image_fusion_add_on_options.check_parameter()
            self.image_fusion_add_on_options.warning_label.setText("")
            json_file = open(data_path("imageFusion.json"), "w", newline="")
            json.dump(image_fusion_add_on_options_values, json_file)
        except ValueError:
            QMessageBox.critical(
                self, "Image Fusion Error",
                "The number of parameters for 'Smooth_Sigmas' and "
                "'Shrink_Factors' do not match.\nPlease try again.")
            save_flag = False
        else:
            json_file.close()

        if save_flag:
            QMessageBox.about(self, "Success",
                              "Changes were successfully applied")

            # Close the Add-On Options Window after saving
            if hasattr(self.window, 'structures_tab'):
                self.window.structures_tab.init_standard_names()
                self.window.structures_tab.update_content()

            self.close()
Exemplo n.º 14
0
    def __init__(self, window):  # initialization function
        super(AddOnOptions, self).__init__()
        # read configuration file for line and fill options
        with open(data_path("line&fill_configuration"), "r") \
                as stream:
            elements = stream.readlines()
            # if file is not empty, each line represents the last saved
            # configuration in the given order
            if len(elements) > 0:
                roi_line = int(elements[0].replace("\n", ""))
                roi_opacity = int(elements[1].replace("\n", ""))
                iso_line = int(elements[2].replace("\n", ""))
                iso_opacity = int(elements[3].replace("\n", ""))
                line_width = float(elements[4].replace("\n", ""))
            else:  # if file is empty for some reason, use the default
                # measures below
                roi_line = 1
                roi_opacity = 10
                iso_line = 2
                iso_opacity = 5
                line_width = 2.0
            stream.close()
        # initialise the UI
        self.window = window
        self.setup_ui(self, roi_line, roi_opacity, iso_line, iso_opacity,
                      line_width)
        # This data is used to create the tree view of functionalities
        # on the left of the window. Each entry will be used as a button
        # to change the view on the right accordingly.
        data = [
            {
                "level": 0,
                "dbID": 442,
                "parent_ID": 6,
                "short_name": "User Options"
            },
            {
                "level": 1,
                "dbID": 522,
                "parent_ID": 442,
                "short_name": "Image Windowing",
            },
            {
                "level": 1,
                "dbID": 556,
                "parent_ID": 442,
                "short_name": "Standard Organ Names",
            },
            {
                "level": 1,
                "dbID": 527,
                "parent_ID": 442,
                "short_name": "Standard Volume Names",
            },
            {
                'level': 1,
                'dbID': 528,
                'parent_ID': 442,
                'short_name': 'Create ROIs from Isodoses'
            },
            {
                "level": 1,
                "dbID": 520,
                "parent_ID": 442,
                "short_name": "Patient ID - Hash ID",
            },
            {
                "level": 1,
                "dbID": 523,
                "parent_ID": 442,
                "short_name": "Line & Fill configuration",
            },
            {
                "level": 0,
                "dbID": 446,
                "parent_ID": 6,
                "short_name": "Configuration"
            },
            {
                "level": 1,
                "dbID": 521,
                "parent_ID": 446,
                "short_name": "Default directory",
            },
            {
                "level": 1,
                "dbID": 530,
                "parent_ID": 446,
                "short_name": "Clinical Data CSV File",
            },
            {
                "level": 0,
                "dbID": 600,
                "parent_ID": 6,
                "short_name": "Image Fusion",
            },
            {
                "level": 1,
                "dbID": 601,
                "parent_ID": 600,
                "short_name": "Auto-Registration",
            },
        ]
        # create a model for the tree view of options and attach the
        # data
        self.model = QtGui.QStandardItemModel()
        self.treeList.setModel(self.model)
        self.import_data(data)
        self.treeList.expandAll()
        # fill the corresponding tables with the corresponding data from
        # the csv files
        self.fill_tables()
        self.treeList.setEditTriggers(QtWidgets.QTreeView.NoEditTriggers
                                      )  # make the tree entries uneditable
        # Functionalities of the Apply and Cancel button
        self.cancel_button.clicked.connect(
            self.close)  # Close the window by discarding all changes
        self.apply_button.clicked.connect(self.accepting)
        # Connecting the functionalities of the view dependant buttons
        self.add_new_window.clicked.connect(self.new_windowing)
        self.delete_window.clicked.connect(self.remove_windowing)
        self.add_standard_organ_name.clicked.connect(self.new_organ)
        self.add_standard_volume_name.clicked.connect(self.new_volume)
        self.add_new_roi.clicked.connect(self.new_isodose)
        self.delete_roi.clicked.connect(self.remove_isodose)
        self.import_organ_csv.clicked.connect(self.import_organs)

        # adding the right click menus for each table
        self.table_view.setContextMenuPolicy(
            QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
        self.table_view.customContextMenuRequested.connect(
            self.onCustomContextMenuRequestedWindow)
        self.table_organ.setContextMenuPolicy(
            QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
        self.table_organ.customContextMenuRequested.connect(
            self.onCustomContextMenuRequestedOrgan)
        self.table_volume.setContextMenuPolicy(
            QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
        self.table_volume.customContextMenuRequested.connect(
            self.onCustomContextMenuRequestedVolume)
        self.table_roi.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.table_roi.customContextMenuRequested.connect(
            self.onCustomContextMenuRequestedRoi)
        # making the URL column a double clicked link
        self.table_organ.itemDoubleClicked.connect(self.open_link)
Exemplo n.º 15
0
matplotlib.cbook.handle_exceptions = "print"  # default
matplotlib.cbook.handle_exceptions = "raise"
matplotlib.cbook.handle_exceptions = "ignore"

# matplotlib.cobook.handle_exceptions = my_logger
# will be called with exception as argument

# The following code are global functions and data/variables used by both
# Clinical Data form and Display classes

# This variable holds the errors messages of the Clinical data form
message = ""

# reading the csv files containing the available diseases
with open(data_path('ICD10_Topography.csv'), 'r') as f:
    reader = csv.reader(f)
    icd = list(reader)
    icd.pop(0)
with open(data_path('ICD10_Topography_C.csv'), 'r') as f:
    reader = csv.reader(f)
    icdc = list(reader)
    icdc.pop(0)
with open(data_path('ICD10_Morphology.csv'), 'r') as f:
    reader = csv.reader(f)
    hist = list(reader)
    hist.pop(0)

# Creating the arrays containing the above data and formatting them
# appropriately
new_icd = []
Exemplo n.º 16
0
def create_moving_model():
    """
    This function initializes all the attributes in the
    MovingDictContainer model required for the operation of the main
    window. This should be called before the
    main window's components are constructed, but after the initial
    values of the MovingDictContainer instance are set (i.e. dataset
    and filepaths).
    """
    ##############################
    #  LOAD PATIENT INFORMATION  #
    ##############################
    moving_dict_container = MovingDictContainer()

    dataset = moving_dict_container.dataset
    filepaths = moving_dict_container.filepaths
    moving_dict_container.set("rtss_modified_moving", False)

    # Determine if dataset is CT for aditional rescaling
    is_ct = False
    if dataset[0].Modality == "CT":
        is_ct = True

    if 'WindowWidth' in dataset[0]:
        if isinstance(dataset[0].WindowWidth, pydicom.valuerep.DSfloat):
            window = int(dataset[0].WindowWidth)
        elif isinstance(dataset[0].WindowWidth, pydicom.multival.MultiValue):
            window = int(dataset[0].WindowWidth[1])
    else:
        window = int(400)

    if 'WindowCenter' in dataset[0]:
        if isinstance(dataset[0].WindowCenter, pydicom.valuerep.DSfloat):
            level = int(dataset[0].WindowCenter) - window / 2
        elif isinstance(dataset[0].WindowCenter, pydicom.multival.MultiValue):
            level = int(dataset[0].WindowCenter[1]) - window / 2
        if is_ct:
            level += CT_RESCALE_INTERCEPT
    else:
        level = int(800)

    moving_dict_container.set("window", window)
    moving_dict_container.set("level", level)

    # Check to see if the imageWindowing.csv file exists
    if os.path.exists(data_path('imageWindowing.csv')):
        # If it exists, read data from file into the self.dict_windowing
        # variable
        dict_windowing = {}
        with open(data_path('imageWindowing.csv'), "r") \
                as fileInput:
            next(fileInput)
            dict_windowing["Normal"] = [window, level]
            for row in fileInput:
                # Format: Organ - Scan - Window - Level
                items = [item for item in row.split(',')]
                dict_windowing[items[0]] = [int(items[2]), int(items[3])]
    else:
        # If csv does not exist, initialize dictionary with default
        # values
        dict_windowing = {
            "Normal": [window, level],
            "Lung": [1600, -300],
            "Bone": [1400, 700],
            "Brain": [160, 950],
            "Soft Tissue": [400, 800],
            "Head and Neck": [275, 900]
        }

    moving_dict_container.set("dict_windowing_moving", dict_windowing)

    if not moving_dict_container.has_attribute("scaled"):
        moving_dict_container.set("scaled", True)
        pixel_values = convert_raw_data(dataset, False, is_ct)
    else:
        pixel_values = convert_raw_data(dataset, True)

    # Calculate the ratio between x axis and y axis of 3 views
    pixmap_aspect = {}
    pixel_spacing = dataset[0].PixelSpacing
    slice_thickness = dataset[0].SliceThickness
    pixmap_aspect["axial"] = pixel_spacing[1] / pixel_spacing[0]
    pixmap_aspect["sagittal"] = pixel_spacing[1] / slice_thickness
    pixmap_aspect["coronal"] = slice_thickness / pixel_spacing[0]
    pixmaps_axial, pixmaps_coronal, pixmaps_sagittal = \
        get_pixmaps(pixel_values, window, level, pixmap_aspect)

    moving_dict_container.set("pixmaps_axial", pixmaps_axial)
    moving_dict_container.set("pixmaps_coronal", pixmaps_coronal)
    moving_dict_container.set("pixmaps_sagittal", pixmaps_sagittal)
    moving_dict_container.set("pixel_values", pixel_values)
    moving_dict_container.set("pixmap_aspect", pixmap_aspect)

    basic_info = get_basic_info(dataset[0])
    moving_dict_container.set("basic_info", basic_info)

    moving_dict_container.set("dict_uid", dict_instance_uid(dataset))

    # Set RTSS attributes
    if moving_dict_container.has_modality("rtss"):
        moving_dict_container.set("file_rtss", filepaths['rtss'])
        moving_dict_container.set("dataset_rtss", dataset['rtss'])

        dicom_tree_rtss = DicomTree(filepaths['rtss'])
        moving_dict_container.set("dict_dicom_tree_rtss", dicom_tree_rtss.dict)

        moving_dict_container.set(
            "list_roi_numbers",
            ordered_list_rois(moving_dict_container.get("rois")))
        moving_dict_container.set("selected_rois", [])

        moving_dict_container.set("dict_polygons", {})

    # Set RTDOSE attributes
    if moving_dict_container.has_modality("rtdose"):
        dicom_tree_rtdose = DicomTree(filepaths['rtdose'])
        moving_dict_container.set("dict_dicom_tree_rtdose",
                                  dicom_tree_rtdose.dict)

        moving_dict_container.set("dose_pixluts", get_dose_pixluts(dataset))

        moving_dict_container.set("selected_doses", [])
        # This will be overwritten if an RTPLAN is present.
        moving_dict_container.set("rx_dose_in_cgray", 1)

    # Set RTPLAN attributes
    if moving_dict_container.has_modality("rtplan"):
        rx_dose_in_cgray = calculate_rx_dose_in_cgray(dataset["rtplan"])
        moving_dict_container.set("rx_dose_in_cgray", rx_dose_in_cgray)

        dicom_tree_rtplan = DicomTree(filepaths['rtplan'])
        moving_dict_container.set("dict_dicom_tree_rtplan",
                                  dicom_tree_rtplan.dict)
Exemplo n.º 17
0
def create_initial_model():
    """
    This function initializes all the attributes in the PatientDictContainer
    model required for the operation of the main window. This should be
    called before the main window's components are constructed, but after
    the initial values of the PatientDictContainer instance are set (i.e.
    dataset and filepaths).
    """
    ##############################
    #  LOAD PATIENT INFORMATION  #
    ##############################
    patient_dict_container = PatientDictContainer()

    dataset = patient_dict_container.dataset
    filepaths = patient_dict_container.filepaths
    patient_dict_container.set("rtss_modified", False)

    # Determine if dataset is CT for aditional rescaling
    is_ct = False
    if dataset[0].Modality == "CT":
        is_ct = True

    if 'WindowWidth' in dataset[0]:
        if isinstance(dataset[0].WindowWidth, pydicom.valuerep.DSfloat):
            window = int(dataset[0].WindowWidth)
        elif isinstance(dataset[0].WindowWidth, pydicom.multival.MultiValue):
            window = int(dataset[0].WindowWidth[1])
    else:
        window = int(400)

    if 'WindowCenter' in dataset[0]:
        if isinstance(dataset[0].WindowCenter, pydicom.valuerep.DSfloat):
            level = int(dataset[0].WindowCenter) - window / 2
        elif isinstance(dataset[0].WindowCenter, pydicom.multival.MultiValue):
            level = int(dataset[0].WindowCenter[1]) - window / 2
        if is_ct:
            level += CT_RESCALE_INTERCEPT
    else:
        level = int(800)

    patient_dict_container.set("window", window)
    patient_dict_container.set("level", level)

    # Check to see if the imageWindowing.csv file exists
    if os.path.exists(data_path('imageWindowing.csv')):
        # If it exists, read data from file into the self.dict_windowing
        # variable
        dict_windowing = {}
        with open(data_path('imageWindowing.csv'), "r") \
                as fileInput:
            next(fileInput)
            dict_windowing["Normal"] = [window, level]
            for row in fileInput:
                # Format: Organ - Scan - Window - Level
                items = [item for item in row.split(',')]
                dict_windowing[items[0]] = [int(items[2]), int(items[3])]
    else:
        # If csv does not exist, initialize dictionary with default values
        dict_windowing = {
            "Normal": [window, level],
            "Lung": [1600, -300],
            "Bone": [1400, 700],
            "Brain": [160, 950],
            "Soft Tissue": [400, 800],
            "Head and Neck": [275, 900]
        }

    patient_dict_container.set("dict_windowing", dict_windowing)

    if not patient_dict_container.has_attribute("scaled"):
        patient_dict_container.set("scaled", True)
        pixel_values = convert_raw_data(dataset, False, is_ct)
    else:
        pixel_values = convert_raw_data(dataset, True)

    # Calculate the ratio between x axis and y axis of 3 views
    pixmap_aspect = {}
    pixel_spacing = dataset[0].PixelSpacing
    slice_thickness = dataset[0].SliceThickness
    pixmap_aspect["axial"] = pixel_spacing[1] / pixel_spacing[0]
    pixmap_aspect["sagittal"] = pixel_spacing[1] / slice_thickness
    pixmap_aspect["coronal"] = slice_thickness / pixel_spacing[0]
    pixmaps_axial, pixmaps_coronal, pixmaps_sagittal = \
        get_pixmaps(pixel_values, window, level, pixmap_aspect)

    patient_dict_container.set("pixmaps_axial", pixmaps_axial)
    patient_dict_container.set("pixmaps_coronal", pixmaps_coronal)
    patient_dict_container.set("pixmaps_sagittal", pixmaps_sagittal)
    patient_dict_container.set("pixel_values", pixel_values)
    patient_dict_container.set("pixmap_aspect", pixmap_aspect)

    basic_info = get_basic_info(dataset[0])
    patient_dict_container.set("basic_info", basic_info)

    patient_dict_container.set("dict_uid", dict_instance_uid(dataset))

    # Set RTSS attributes
    patient_dict_container.set("file_rtss", filepaths['rtss'])
    patient_dict_container.set("dataset_rtss", dataset['rtss'])
    dict_raw_contour_data, dict_numpoints = \
        ImageLoading.get_raw_contour_data(dataset['rtss'])
    patient_dict_container.set("raw_contour", dict_raw_contour_data)

    # dict_dicom_tree_rtss will be set in advance if the program
    # generates a new rtss through the execution of
    # ROI.create_initial_rtss_from_ct(...)
    if patient_dict_container.get("dict_dicom_tree_rtss") is None:
        dicom_tree_rtss = DicomTree(filepaths['rtss'])
        patient_dict_container.set("dict_dicom_tree_rtss",
                                   dicom_tree_rtss.dict)

    patient_dict_container.set(
        "list_roi_numbers",
        ordered_list_rois(patient_dict_container.get("rois")))
    patient_dict_container.set("selected_rois", [])

    patient_dict_container.set("dict_polygons_axial", {})
    patient_dict_container.set("dict_polygons_sagittal", {})
    patient_dict_container.set("dict_polygons_coronal", {})

    # Set RTDOSE attributes
    if patient_dict_container.has_modality("rtdose"):
        dicom_tree_rtdose = DicomTree(filepaths['rtdose'])
        patient_dict_container.set("dict_dicom_tree_rtdose",
                                   dicom_tree_rtdose.dict)

        patient_dict_container.set("dose_pixluts", get_dose_pixluts(dataset))

        patient_dict_container.set("selected_doses", [])

        # overwritten if RTPLAN is present.
        patient_dict_container.set("rx_dose_in_cgray", 1)

    # Set RTPLAN attributes
    if patient_dict_container.has_modality("rtplan"):
        # the TargetPrescriptionDose is type 3 (optional), so it may not be
        # there However, it is preferable to the sum of the beam doses
        # DoseReferenceStructureType is type 1 (value is mandatory), but it
        # can have a value of ORGAN_AT_RISK rather than TARGET in which case
        # there will *not* be a TargetPrescriptionDose and even if it is
        # TARGET, that's no guarantee that TargetPrescriptionDose will be
        # encoded and have a value
        rx_dose_in_cgray = calculate_rx_dose_in_cgray(dataset["rtplan"])
        patient_dict_container.set("rx_dose_in_cgray", rx_dose_in_cgray)

        dicom_tree_rtplan = DicomTree(filepaths['rtplan'])
        patient_dict_container.set("dict_dicom_tree_rtplan",
                                   dicom_tree_rtplan.dict)

    # Set SR attributes
    if patient_dict_container.has_modality("sr-cd"):
        dicom_tree_sr_clinical_data = DicomTree(filepaths['sr-cd'])
        patient_dict_container.set("dict_dicom_tree_sr_cd",
                                   dicom_tree_sr_clinical_data.dict)

    if patient_dict_container.has_modality("sr-rad"):
        dicom_tree_sr_pyrad = DicomTree(filepaths['sr-rad'])
        patient_dict_container.set("dict_dicom_tree_sr_pyrad",
                                   dicom_tree_sr_pyrad.dict)