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
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
def start(self): """ Goes through the steps of the DVH2CSV conversion. :return: True if successful, False if not. """ # Stop loading if self.interrupt_flag.is_set(): self.patient_dict_container.clear() self.summary = "INTERRUPT" return False if not self.ready: self.summary = "SKIP" return False # Check if the dataset is complete self.progress_callback.emit(("Checking dataset...", 40)) # Attempt to get DVH data from RT Dose self.progress_callback.emit( ("Attempting to get DVH from RTDOSE...", 50)) # Get DVH data raw_dvh = CalculateDVHs.rtdose2dvh() # If there is DVH data dvh_outdated = True if bool(raw_dvh): incomplete = raw_dvh["diff"] raw_dvh.pop("diff") if not incomplete: dvh_outdated = False self.progress_callback.emit(("DVH data in RT Dose.", 80)) else: raw_dvh.pop("diff") if dvh_outdated: # Calculate DVH if not in RT Dose self.progress_callback.emit(("Calculating DVH...", 60)) read_data_dict = self.patient_dict_container.dataset dataset_rtss = self.patient_dict_container.dataset['rtss'] dataset_rtdose = self.patient_dict_container.dataset['rtdose'] rois = self.patient_dict_container.get("rois") try: dict_thickness = \ ImageLoading.get_thickness_dict(dataset_rtss, read_data_dict) raw_dvh = ImageLoading.calc_dvhs(dataset_rtss, dataset_rtdose, rois, dict_thickness, self.interrupt_flag) except TypeError: self.summary = "DVH_TYPE_ERROR" return False # Stop loading if self.interrupt_flag.is_set(): self.patient_dict_container.clear() self.summary = "INTERRUPT" return False # Export DVH to CSV self.progress_callback.emit(("Exporting DVH to CSV...", 90)) # Get path to save to path = self.output_path + '/CSV/' # Get patient ID patient_id = self.patient_dict_container.dataset['rtss'].PatientID # Make CSV directory if it doesn't exist if not os.path.isdir(path): os.mkdir(path) # Save the DVH to a CSV file self.progress_callback.emit(("Exporting DVH to RT Dose...", 95)) self.dvh2csv(raw_dvh, path, self.filename, patient_id) # Save the DVH to the RT Dose CalculateDVHs.dvh2rtdose(raw_dvh) return True