Ejemplo n.º 1
0
    def __init__(self):
        # Load test DICOM files
        desired_path = Path.cwd().joinpath('test', 'testdata')
        selected_files = find_DICOM_files(desired_path)  # list of DICOM test files
        file_path = os.path.dirname(os.path.commonprefix(selected_files))  # file path of DICOM files
        read_data_dict, file_names_dict = ImageLoading.get_datasets(selected_files)

        # Create patient dict container object
        patient_dict_container = PatientDictContainer()
        patient_dict_container.clear()
        patient_dict_container.set_initial_values(file_path, read_data_dict, file_names_dict)

        # Set additional attributes in patient dict container (otherwise program will crash and test will fail)
        if "rtss" in file_names_dict:
            dataset_rtss = dcmread(file_names_dict['rtss'])
            self.rois = ImageLoading.get_roi_info(dataset_rtss)
            dict_raw_contour_data, dict_numpoints = ImageLoading.get_raw_contour_data(dataset_rtss)
            dict_pixluts = ImageLoading.get_pixluts(read_data_dict)

            patient_dict_container.set("rois", self.rois)
            patient_dict_container.set("raw_contour", dict_raw_contour_data)
            patient_dict_container.set("num_points", dict_numpoints)
            patient_dict_container.set("pixluts", dict_pixluts)

        # Open the main window
        self.main_window = MainWindow()
    def __init__(self):
        # Load test DICOM files
        if platform.system() == "Windows":
            desired_path = "\\testdata\\DICOM-RT-TEST"
        elif platform.system() == "Linux" or platform.system() == "Darwin":
            desired_path = "/testdata/DICOM-RT-TEST"

        desired_path = os.path.dirname(
            os.path.realpath(__file__)) + desired_path

        selected_files = find_DICOM_files(
            desired_path)  # list of DICOM test files
        file_path = os.path.dirname(
            os.path.commonprefix(selected_files))  # file path of DICOM files
        read_data_dict, file_names_dict = ImageLoading.get_datasets(
            selected_files)

        # Create patient dict container object
        patient_dict_container = PatientDictContainer()
        patient_dict_container.clear()
        patient_dict_container.set_initial_values(file_path, read_data_dict,
                                                  file_names_dict)

        # Set additional attributes in patient dict container (otherwise program will crash and test will fail)
        if "rtss" in file_names_dict:
            dataset_rtss = dcmread(file_names_dict['rtss'])
            self.rois = ImageLoading.get_roi_info(dataset_rtss)
            dict_raw_contour_data, dict_numpoints = ImageLoading.get_raw_contour_data(
                dataset_rtss)
            dict_pixluts = ImageLoading.get_pixluts(read_data_dict)

            patient_dict_container.set("rois", self.rois)
            patient_dict_container.set("raw_contour", dict_raw_contour_data)
            patient_dict_container.set("num_points", dict_numpoints)
            patient_dict_container.set("pixluts", dict_pixluts)

        # Open the main window
        self.main_window = MainWindow()
        self.main_window.show()

        self.dicom_view = self.main_window.dicom_view
        self.new_polygons = {}
        slider_id = self.dicom_view.slider.value()
        self.curr_slice = self.dicom_view.patient_dict_container.get(
            "dict_uid")[slider_id]
Ejemplo n.º 3
0
    def __init__(self):
        # Load test DICOM files
        desired_path = Path.cwd().joinpath('test', 'pet-testdata')

        # List of DICOM test files
        selected_files = find_DICOM_files(desired_path)

        # File path of DICOM files
        file_path = os.path.dirname(os.path.commonprefix(selected_files))
        read_data_dict, file_names_dict = \
            ImageLoading.get_datasets(selected_files)

        # Create patient dict container object
        self.patient_dict_container = PatientDictContainer()
        self.patient_dict_container.clear()
        self.patient_dict_container.set_initial_values \
            (file_path, read_data_dict, file_names_dict)

        # Set additional attributes in patient dict container
        # (otherwise program will crash and test will fail)
        self.patient_dict_container.set("existing_rtss_files", [])
        if "rtss" in file_names_dict:
            dataset_rtss = dcmread(file_names_dict['rtss'])
            self.rois = ImageLoading.get_roi_info(dataset_rtss)
            dict_raw_contour_data, dict_numpoints = \
                ImageLoading.get_raw_contour_data(dataset_rtss)
            dict_pixluts = ImageLoading.get_pixluts(read_data_dict)

            self.patient_dict_container.set("rois", self.rois)
            self.patient_dict_container.set("raw_contour",
                                            dict_raw_contour_data)
            self.patient_dict_container.set("num_points", dict_numpoints)
            self.patient_dict_container.set("pixluts", dict_pixluts)
        else:
            img_loader = ImageLoader(selected_files, None, None)
            img_loader.load_temp_rtss(file_path, DummyProgressWindow,
                                      DummyProgressWindow)

        # Open the main window
        self.main_window = MainWindow()

        # Get the initial structure and ROI count
        self.initial_structure_count = \
            self.main_window.structures_tab.layout_content.count()
        self.initial_roi_count = len(self.main_window.structures_tab.rois)
Ejemplo n.º 4
0
    def structure_modified(self, new_dataset):
        """
		Executes when a structure is renamed/deleted. Displays indicator that structure has changed.
		"""
        # TODO there needs to be a way to give the user the option to save the new RTSS file.
        # Currently all changes are discarded when the user exits the program.

        # If this is the first time the RTSS has been modified, create a modified indicator giving the user the option
        # to save their new file.
        if not self.main_window.rtss_modified:

            modified_indicator_widget = QtWidgets.QWidget()
            modified_indicator_widget.setContentsMargins(8, 5, 8, 5)
            modified_indicator_layout = QtWidgets.QHBoxLayout()
            modified_indicator_layout.setAlignment(Qt.AlignLeft)

            modified_indicator_icon = QtWidgets.QLabel()
            modified_indicator_icon.setPixmap(
                QtGui.QPixmap("src/Icon/alert.png"))
            modified_indicator_layout.addWidget(modified_indicator_icon)

            modified_indicator_text = QtWidgets.QLabel(
                "Structures have been modified")
            modified_indicator_text.setStyleSheet("color: red")
            modified_indicator_layout.addWidget(modified_indicator_text)

            modified_indicator_widget.setLayout(modified_indicator_layout)
            modified_indicator_widget.mouseReleaseEvent = self.save_new_rtss  # When the widget is clicked, save the rtss
            self.layout.addWidget(modified_indicator_widget)

        # If this is the first change made to the RTSS file, update the dataset with the new one so that OnkoDICOM
        # starts working off this dataset rather than the original RTSS file.
        self.main_window.rtss_modified = True
        self.main_window.dataset_rtss = new_dataset

        # Refresh ROIs in main page
        self.main_window.rois = ImageLoading.get_roi_info(new_dataset)
        self.main_window.dict_raw_ContourData, self.main_window.dict_NumPoints = ImageLoading.get_raw_contour_data(
            new_dataset)
        self.main_window.list_roi_numbers = self.main_window.ordered_list_rois(
        )

        # Refresh structure tab
        self.update_content()
Ejemplo n.º 5
0
    def __init__(self):
        # Load test DICOM files
        desired_path = Path.cwd().joinpath('test', 'testdata')

        # list of DICOM test files
        selected_files = find_DICOM_files(desired_path)
        # file path of DICOM files
        file_path = os.path.dirname(os.path.commonprefix(selected_files))
        read_data_dict, file_names_dict = \
            ImageLoading.get_datasets(selected_files)

        # Create patient dict container object
        self.patient_dict_container = PatientDictContainer()
        self.patient_dict_container.clear()
        self.patient_dict_container.set_initial_values\
            (file_path, read_data_dict, file_names_dict)

        # Set additional attributes in patient dict container
        # (otherwise program will crash and test will fail)
        if "rtss" in file_names_dict:
            dataset_rtss = dcmread(file_names_dict['rtss'])
            self.rois = ImageLoading.get_roi_info(dataset_rtss)
            dict_raw_contour_data, dict_numpoints = \
                ImageLoading.get_raw_contour_data(dataset_rtss)
            dict_pixluts = ImageLoading.get_pixluts(read_data_dict)

            self.patient_dict_container.set("rois", self.rois)
            self.patient_dict_container.set("raw_contour",
                                            dict_raw_contour_data)
            self.patient_dict_container.set("num_points", dict_numpoints)
            self.patient_dict_container.set("pixluts", dict_pixluts)

            # Set location of rtss file
            file_paths = self.patient_dict_container.filepaths
            self.patient_dict_container.set("file_rtss", file_paths['rtss'])

        # Create ISO2ROI object
        self.iso2roi = ISO2ROI()
Ejemplo n.º 6
0
    def load(self, interrupt_flag, progress_callback):
        """
        :param interrupt_flag: A threading.Event() object that tells the 
        function to stop loading.

        :param progress_callback: A signal that receives the current 
        progress of the loading.

        :return: PatientDictContainer object containing all values related 
        to the loaded DICOM files.
        """
        progress_callback.emit(("Creating datasets...", 0))
        try:
            # Gets the common root folder.
            path = os.path.dirname(os.path.commonprefix(self.selected_files))
            read_data_dict, file_names_dict = ImageLoading.get_datasets(
                self.selected_files)
        except ImageLoading.NotAllowedClassError:
            raise ImageLoading.NotAllowedClassError

        # Populate the initial values in the PatientDictContainer singleton.
        moving_dict_container = MovingDictContainer()
        moving_dict_container.clear()
        moving_dict_container.set_initial_values(
            path,
            read_data_dict,
            file_names_dict,
            existing_rtss_files=self.existing_rtss)

        if interrupt_flag.is_set():
            print("stopped")
            return False

        if 'rtss' in file_names_dict and 'rtdose' in file_names_dict:
            self.parent_window.signal_advise_calc_dvh.connect(
                self.update_calc_dvh)
            self.signal_request_calc_dvh.emit()

            while not self.advised_calc_dvh:
                pass

        if 'rtss' in file_names_dict:
            dataset_rtss = dcmread(file_names_dict['rtss'])

            progress_callback.emit(("Getting ROI info...", 10))
            rois = ImageLoading.get_roi_info(dataset_rtss)

            if interrupt_flag.is_set():  # Stop loading.
                print("stopped")
                return False

            progress_callback.emit(("Getting contour data...", 30))
            dict_raw_contour_data, dict_numpoints = \
                ImageLoading.get_raw_contour_data(dataset_rtss)

            # Determine which ROIs are one slice thick
            dict_thickness = ImageLoading.get_thickness_dict(
                dataset_rtss, read_data_dict)

            if interrupt_flag.is_set():  # Stop loading.
                print("stopped")
                return False

            progress_callback.emit(("Getting pixel LUTs...", 50))
            dict_pixluts = ImageLoading.get_pixluts(read_data_dict)

            if interrupt_flag.is_set():  # Stop loading.
                print("stopped")
                return False

            # Add RTSS values to MovingDictContainer
            moving_dict_container.set("rois", rois)
            moving_dict_container.set("raw_contour", dict_raw_contour_data)
            moving_dict_container.set("num_points", dict_numpoints)
            moving_dict_container.set("pixluts", dict_pixluts)

            if 'rtdose' in file_names_dict and self.calc_dvh:
                dataset_rtdose = dcmread(file_names_dict['rtdose'])

                # Spawn-based platforms (i.e Windows and MacOS) have a large
                # overhead when creating a new process, which ends up making
                # multiprocessing on these platforms more expensive than linear
                # calculation. As such, multiprocessing is only available on
                # Linux until a better solution is found.
                fork_safe_platforms = ['Linux']
                if platform.system() in fork_safe_platforms:
                    progress_callback.emit(("Calculating DVHs...", 60))
                    raw_dvh = ImageLoading.multi_calc_dvh(
                        dataset_rtss, dataset_rtdose, rois, dict_thickness)
                else:
                    progress_callback.emit(
                        ("Calculating DVHs... (This may take a while)", 60))
                    raw_dvh = ImageLoading.calc_dvhs(dataset_rtss,
                                                     dataset_rtdose, rois,
                                                     dict_thickness,
                                                     interrupt_flag)

                if interrupt_flag.is_set():  # Stop loading.
                    print("stopped")
                    return False

                progress_callback.emit(("Converging to zero...", 80))
                dvh_x_y = ImageLoading.converge_to_0_dvh(raw_dvh)

                if interrupt_flag.is_set():  # Stop loading.
                    print("stopped")
                    return False

                # Add DVH values to MovingDictContainer
                moving_dict_container.set("raw_dvh", raw_dvh)
                moving_dict_container.set("dvh_x_y", dvh_x_y)
                moving_dict_container.set("dvh_outdated", False)
            create_moving_model()
        else:
            create_moving_model()
            self.load_temp_rtss(path, progress_callback, interrupt_flag)
        progress_callback.emit(("Loading Moving Model", 85))

        if interrupt_flag.is_set():  # Stop loading.
            progress_callback.emit(("Stopping", 85))
            return False

        return True
Ejemplo n.º 7
0
    def fixed_container_structure_modified(self, changes):
        """
        Executes when a structure of fixed patient container is modified
        Displays indicator that structure has changed.
        Changes is a tuple of (new_dataset,
        description_of_changes)
        description_of_changes follows the format
        {"type_of_change": value_of_change}.
        Examples:
        {"rename": ["TOOTH", "TEETH"]} represents that the TOOTH structure has
            been renamed to TEETH.
        {"delete": ["TEETH", "MAXILLA"]} represents that the TEETH and MAXILLA
            structures have been deleted.
        {"draw": "AORTA"} represents that a new structure AORTA has been drawn.
        Note: Use {"draw": None} after multiple ROIs are generated
        (E.g., from ISO2ROI functionality), and use {"transfer":None} for
         ROI Transfer instead of calling this function
        multiple times. This will trigger auto save.
        """

        new_dataset = changes[0]
        change_description = changes[1]

        # Only show the modified indicator if description_of_changes is
        # not {"draw": None}, as this description means that the RTSS
        # is autosaved, and therefore there is no need to tell the user
        # that the RTSS has been modified
        if not("draw" in change_description
               and change_description["draw"] is None) and \
                not ("transfer" in change_description):
            self.show_modified_indicator()

        # If this is the first change made to the RTSS file, update the
        # dataset with the new one so that OnkoDICOM starts working off this
        # dataset rather than the original RTSS file.
        self.patient_dict_container.set("rtss_modified", True)
        self.patient_dict_container.set("dataset_rtss", new_dataset)

        # Refresh ROIs in main page
        self.patient_dict_container.set("rois",
                                        ImageLoading.get_roi_info(new_dataset))
        self.rois = self.patient_dict_container.get("rois")
        contour_data = ImageLoading.get_raw_contour_data(new_dataset)
        self.patient_dict_container.set("raw_contour", contour_data[0])
        self.patient_dict_container.set("num_points", contour_data[1])
        pixluts = ImageLoading.get_pixluts(self.patient_dict_container.dataset)
        self.patient_dict_container.set("pixluts", pixluts)
        self.patient_dict_container.set(
            "list_roi_numbers",
            ordered_list_rois(self.patient_dict_container.get("rois")))
        self.patient_dict_container.set("selected_rois", [])
        self.patient_dict_container.set("dict_polygons_axial", {})
        self.patient_dict_container.set("dict_polygons_sagittal", {})
        self.patient_dict_container.set("dict_polygons_coronal", {})

        if "draw" in change_description or "transfer" in change_description:
            dicom_tree_rtss = DicomTree(None)
            dicom_tree_rtss.dataset = new_dataset
            dicom_tree_rtss.dict = dicom_tree_rtss.dataset_to_dict(
                dicom_tree_rtss.dataset)
            self.patient_dict_container.set("dict_dicom_tree_rtss",
                                            dicom_tree_rtss.dict)
            self.color_dict = self.init_color_roi(self.patient_dict_container)
            self.patient_dict_container.set("roi_color_dict", self.color_dict)
            if self.patient_dict_container.has_attribute("raw_dvh"):
                # DVH will be outdated once changes to it are made, and
                # recalculation will be required.
                self.patient_dict_container.set("dvh_outdated", True)

        if self.patient_dict_container.has_attribute("raw_dvh"):
            # Rename structures in DVH list
            if "rename" in change_description:
                new_raw_dvh = self.patient_dict_container.get("raw_dvh")
                for key, dvh in new_raw_dvh.items():
                    if dvh.name == change_description["rename"][0]:
                        dvh.name = change_description["rename"][1]
                        break

                self.patient_dict_container.set("raw_dvh", new_raw_dvh)
                dvh2rtdose(new_raw_dvh)

            # Remove structures from DVH list - the only visible effect of
            # this section is the exported DVH csv
            if "delete" in change_description:
                list_of_deleted = []
                new_raw_dvh = self.patient_dict_container.get("raw_dvh")
                for key, dvh in new_raw_dvh.items():
                    if dvh.name in change_description["delete"]:
                        list_of_deleted.append(key)
                for key in list_of_deleted:
                    new_raw_dvh.pop(key)
                self.patient_dict_container.set("raw_dvh", new_raw_dvh)
                dvh2rtdose(new_raw_dvh)

        # Refresh ROIs in DVH tab and DICOM View
        self.request_update_structures.emit()

        # Refresh structure tab
        self.update_content()

        if "draw" in change_description and change_description["draw"] is None:
            self.save_new_rtss_to_fixed_image_set(auto=True)
        elif "transfer" in change_description \
                and change_description["transfer"] is None:
            self.save_new_rtss_to_fixed_image_set(auto=True)
Ejemplo n.º 8
0
    def structure_modified(self, changes):
        """
		Executes when a structure is renamed/deleted. Displays indicator that structure has changed.
		changes is a tuple of (new_dataset, description_of_changes)
		description_of_changes follows the format {"type_of_change": value_of_change}.
		Examples: {"rename": ["TOOTH", "TEETH"]} represents that the TOOTH structure has been renamed to TEETH.
		{"delete": ["TEETH", "MAXILLA"]} represents that the TEETH and MAXILLA structures have been deleted.
		"""

        new_dataset = changes[0]
        change_description = changes[1]

        # If this is the first time the RTSS has been modified, create a modified indicator giving the user the option
        # to save their new file.
        if not self.main_window.rtss_modified:

            modified_indicator_widget = QtWidgets.QWidget()
            modified_indicator_widget.setContentsMargins(8, 5, 8, 5)
            modified_indicator_layout = QtWidgets.QHBoxLayout()
            modified_indicator_layout.setAlignment(Qt.AlignLeft)

            modified_indicator_icon = QtWidgets.QLabel()
            modified_indicator_icon.setPixmap(
                QtGui.QPixmap("src/Icon/alert.png"))
            modified_indicator_layout.addWidget(modified_indicator_icon)

            modified_indicator_text = QtWidgets.QLabel(
                "Structures have been modified")
            modified_indicator_text.setStyleSheet("color: red")
            modified_indicator_layout.addWidget(modified_indicator_text)

            modified_indicator_widget.setLayout(modified_indicator_layout)
            modified_indicator_widget.mouseReleaseEvent = self.save_new_rtss  # When the widget is clicked, save the rtss
            self.layout.addWidget(modified_indicator_widget)

        # If this is the first change made to the RTSS file, update the dataset with the new one so that OnkoDICOM
        # starts working off this dataset rather than the original RTSS file.
        self.main_window.rtss_modified = True
        self.main_window.dataset_rtss = new_dataset

        # Refresh ROIs in main page
        self.main_window.rois = ImageLoading.get_roi_info(new_dataset)
        self.main_window.dict_raw_ContourData, self.main_window.dict_NumPoints = ImageLoading.get_raw_contour_data(
            new_dataset)
        self.main_window.list_roi_numbers = self.main_window.ordered_list_rois(
        )
        self.main_window.selected_rois = []

        if self.main_window.raw_dvh is not None:
            # Rename structures in DVH list
            if "rename" in changes[1]:
                for key, dvh in self.main_window.raw_dvh.items():
                    if dvh.name == change_description["rename"][0]:
                        dvh.name = change_description["rename"][1]
                        break

            # Remove structures from DVH list - the only visible effect of this section is the exported DVH csv
            if "delete" in changes[1]:
                list_of_deleted = []
                for key, dvh in self.main_window.raw_dvh.items():
                    if dvh.name in change_description["delete"]:
                        list_of_deleted.append(key)
                for key in list_of_deleted:
                    self.main_window.raw_dvh.pop(key)

        # Refresh ROIs in DVH tab and DICOM View
        if hasattr(self.main_window, 'dvh'):
            self.main_window.dvh.update_plot(self.main_window)
        self.main_window.dicom_view.update_view()

        # Refresh structure tab
        self.update_content()
Ejemplo n.º 9
0
    def load(self, interrupt_flag, progress_callback):
        """
        :param interrupt_flag: A threading.Event() object that tells the function to stop loading.
        :param progress_callback: A signal that receives the current progress of the loading.
        :return: PatientDictContainer object containing all values related to the loaded DICOM files.
        """
        progress_callback.emit(("Creating datasets...", 0))
        try:
            path = os.path.dirname(os.path.commonprefix(self.selected_files))  # Gets the common root folder.
            read_data_dict, file_names_dict = ImageLoading.get_datasets(self.selected_files)
        except ImageLoading.NotAllowedClassError:
            raise ImageLoading.NotAllowedClassError

        # Populate the initial values in the PatientDictContainer singleton.
        patient_dict_container = PatientDictContainer()
        patient_dict_container.clear()
        patient_dict_container.set_initial_values(path, read_data_dict, file_names_dict)

        # As there is no way to interrupt a QRunnable, this method must check after every step whether or not the
        # interrupt flag has been set, in which case it will interrupt this method after the currently processing
        # function has finished running. It's not very pretty, and the thread will still run some functions for, in some
        # cases, up to a couple seconds after the close button on the Progress Window has been clicked, however it's
        # the best solution I could come up with. If you have a cleaner alternative, please make your contribution.
        if interrupt_flag.is_set():
            print("stopped")
            return False

        if 'rtss' in file_names_dict and 'rtdose' in file_names_dict:
            self.parent_window.signal_advise_calc_dvh.connect(self.update_calc_dvh)
            self.signal_request_calc_dvh.emit()

            while not self.advised_calc_dvh:
                pass

        if 'rtss' in file_names_dict:
            dataset_rtss = dcmread(file_names_dict['rtss'])

            progress_callback.emit(("Getting ROI info...", 10))
            rois = ImageLoading.get_roi_info(dataset_rtss)

            if interrupt_flag.is_set():  # Stop loading.
                print("stopped")
                return False

            progress_callback.emit(("Getting contour data...", 30))
            dict_raw_contour_data, dict_numpoints = ImageLoading.get_raw_contour_data(dataset_rtss)

            # Determine which ROIs are one slice thick
            dict_thickness = ImageLoading.get_thickness_dict(dataset_rtss, read_data_dict)

            if interrupt_flag.is_set():  # Stop loading.
                print("stopped")
                return False

            progress_callback.emit(("Getting pixel LUTs...", 50))
            dict_pixluts = ImageLoading.get_pixluts(read_data_dict)

            if interrupt_flag.is_set():  # Stop loading.
                print("stopped")
                return False

            # Add RTSS values to PatientDictContainer
            patient_dict_container.set("rois", rois)
            patient_dict_container.set("raw_contour", dict_raw_contour_data)
            patient_dict_container.set("num_points", dict_numpoints)
            patient_dict_container.set("pixluts", dict_pixluts)

            if 'rtdose' in file_names_dict and self.calc_dvh:
                dataset_rtdose = dcmread(file_names_dict['rtdose'])

                # Spawn-based platforms (i.e Windows and MacOS) have a large overhead when creating a new process, which
                # ends up making multiprocessing on these platforms more expensive than linear calculation. As such,
                # multiprocessing is only available on Linux until a better solution is found.
                fork_safe_platforms = ['Linux']
                if platform.system() in fork_safe_platforms:
                    progress_callback.emit(("Calculating DVHs...", 60))
                    raw_dvh = ImageLoading.multi_calc_dvh(dataset_rtss, dataset_rtdose, rois, dict_thickness)
                else:
                    progress_callback.emit(("Calculating DVHs... (This may take a while)", 60))
                    raw_dvh = ImageLoading.calc_dvhs(dataset_rtss, dataset_rtdose, rois, dict_thickness, interrupt_flag)

                if interrupt_flag.is_set():  # Stop loading.
                    print("stopped")
                    return False

                progress_callback.emit(("Converging to zero...", 80))
                dvh_x_y = ImageLoading.converge_to_0_dvh(raw_dvh)

                if interrupt_flag.is_set():  # Stop loading.
                    print("stopped")
                    return False

                # Add DVH values to PatientDictContainer
                patient_dict_container.set("raw_dvh", raw_dvh)
                patient_dict_container.set("dvh_x_y", dvh_x_y)
                patient_dict_container.set("dvh_outdated", False)

                return True
            else:
                return True

        return True
Ejemplo n.º 10
0
    def load_images(cls, patient_files, required_classes):
        """
        Loads required datasets for the selected patient.
        :param patient_files: dictionary of classes and patient files.
        :param required_classes: list of classes required for the
                                 selected/current process.
        :return: True if all required datasets found, false otherwise.
        """
        files = []
        found_classes = set()

        # Loop through each item in patient_files
        for key, value in patient_files.items():
            # If the item is an allowed class
            if key in cls.allowed_classes:
                for i in range(len(value)):
                    # Add item's files to the files list
                    files.extend(value[i].get_files())

                # Get the modality name
                modality_name = cls.allowed_classes.get(key).get('name')

                # If the modality name is not found_classes, add it
                if modality_name not in found_classes \
                        and modality_name in required_classes:
                    found_classes.add(modality_name)

        # Get the difference between required classes and found classes
        class_diff = set(required_classes).difference(found_classes)

        # If the dataset is missing required files, pass on it
        if len(class_diff) > 0:
            print("Skipping dataset. Missing required file(s) {}".format(
                class_diff))
            return False

        # Try to get the datasets from the selected files
        try:
            # Convert paths to a common file system representation
            for i, file in enumerate(files):
                files[i] = Path(file).as_posix()
            read_data_dict, file_names_dict = cls.get_datasets(files)
            path = os.path.dirname(
                os.path.commonprefix(list(file_names_dict.values())))
        # Otherwise raise an exception (OnkoDICOM does not support the
        # selected file type)
        except ImageLoading.NotAllowedClassError:
            raise ImageLoading.NotAllowedClassError

        # Populate the initial values in the PatientDictContainer
        patient_dict_container = PatientDictContainer()
        patient_dict_container.clear()
        patient_dict_container.set_initial_values(path, read_data_dict,
                                                  file_names_dict)

        # If an RT Struct is included, set relevant values in the
        # PatientDictContainer
        if 'rtss' in file_names_dict:
            dataset_rtss = dcmread(file_names_dict['rtss'])
            rois = ImageLoading.get_roi_info(dataset_rtss)
            dict_raw_contour_data, dict_numpoints = \
                ImageLoading.get_raw_contour_data(dataset_rtss)
            dict_pixluts = ImageLoading.get_pixluts(read_data_dict)

            # Add RT Struct values to PatientDictContainer
            patient_dict_container.set("rois", rois)
            patient_dict_container.set("raw_contour", dict_raw_contour_data)
            patient_dict_container.set("num_points", dict_numpoints)
            patient_dict_container.set("pixluts", dict_pixluts)

        return True
Ejemplo n.º 11
0
    def structure_modified(self, changes):
        """
        Executes when a structure is renamed/deleted. Displays indicator that structure has changed.
        changes is a tuple of (new_dataset, description_of_changes)
        description_of_changes follows the format {"type_of_change": value_of_change}.
        Examples: {"rename": ["TOOTH", "TEETH"]} represents that the TOOTH structure has been renamed to TEETH.
        {"delete": ["TEETH", "MAXILLA"]} represents that the TEETH and MAXILLA structures have been deleted.
        {"draw": "AORTA"} represents that a new structure AORTA has been drawn.
        """

        new_dataset = changes[0]
        change_description = changes[1]

        # If this is the first time the RTSS has been modified, create a modified indicator giving the user the option
        # to save their new file.
        if self.patient_dict_container.get("rtss_modified") is False:
            self.show_modified_indicator()

        # If this is the first change made to the RTSS file, update the dataset with the new one so that OnkoDICOM
        # starts working off this dataset rather than the original RTSS file.
        self.patient_dict_container.set("rtss_modified", True)
        self.patient_dict_container.set("dataset_rtss", new_dataset)

        # Refresh ROIs in main page
        self.patient_dict_container.set("rois",
                                        ImageLoading.get_roi_info(new_dataset))
        self.rois = self.patient_dict_container.get("rois")
        contour_data = ImageLoading.get_raw_contour_data(new_dataset)
        self.patient_dict_container.set("raw_contour", contour_data[0])
        self.patient_dict_container.set("num_points", contour_data[1])
        pixluts = ImageLoading.get_pixluts(self.patient_dict_container.dataset)
        self.patient_dict_container.set("pixluts", pixluts)
        self.patient_dict_container.set(
            "list_roi_numbers",
            ordered_list_rois(self.patient_dict_container.get("rois")))
        self.patient_dict_container.set("selected_rois", [])
        self.patient_dict_container.set("dict_polygons", {})

        if "draw" in change_description:
            dicom_tree_rtss = DicomTree(None)
            dicom_tree_rtss.dataset = new_dataset
            dicom_tree_rtss.dict = dicom_tree_rtss.dataset_to_dict(
                dicom_tree_rtss.dataset)
            self.patient_dict_container.set("dict_dicom_tree_rtss",
                                            dicom_tree_rtss.dict)
            self.color_dict = self.init_color_roi()
            self.patient_dict_container.set("roi_color_dict", self.color_dict)
            if self.patient_dict_container.has_attribute("raw_dvh"):
                # DVH will be outdated once changes to it are made, and recalculation will be required.
                self.patient_dict_container.set("dvh_outdated", True)

        if self.patient_dict_container.has_modality("raw_dvh"):
            # Rename structures in DVH list
            if "rename" in changes[1]:
                new_raw_dvh = self.patient_dict_container.get("raw_dvh")
                for key, dvh in new_raw_dvh.items():
                    if dvh.name == change_description["rename"][0]:
                        dvh.name = change_description["rename"][1]
                        break

                self.patient_dict_container.set("raw_dvh", new_raw_dvh)

            # Remove structures from DVH list - the only visible effect of this section is the exported DVH csv
            if "delete" in changes[1]:
                list_of_deleted = []
                new_raw_dvh = self.patient_dict_container.get("raw_dvh")
                for key, dvh in new_raw_dvh.items():
                    if dvh.name in change_description["delete"]:
                        list_of_deleted.append(key)
                for key in list_of_deleted:
                    new_raw_dvh.pop(key)
                self.patient_dict_container.set("raw_dvh", new_raw_dvh)

        # Refresh ROIs in DVH tab and DICOM View
        self.request_update_structures.emit()

        # Refresh structure tab
        self.update_content()
Ejemplo n.º 12
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)
Ejemplo n.º 13
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)