def __init__(self, progress_callback, interrupt_flag, patient_files, input_path): """ Class initialiser function. :param progress_callback: A signal that receives the current progress of the loading. :param interrupt_flag: A threading.Event() object that tells the function to stop loading. :param patient_files: List of patient files. :param output_path: Path of the input CSV file. """ # Call the parent class super(BatchProcessCSV2ClinicalDataSR, self).__init__(progress_callback, interrupt_flag, patient_files) # Set class variables self.patient_dict_container = PatientDictContainer() self.required_classes = ['ct', 'rtdose'] self.required_classes_2 = ['pet', 'rtdose'] # Only need one of either ct or pet (and rtdose) self.ready = False ready = self.load_images(patient_files, self.required_classes) if ready: self.ready = True else: self.ready = \ self.load_images(patient_files, self.required_classes_2) self.input_path = input_path
def onSaveClicked(self): """ Save the new ROI """ # Get the name of the new ROI new_roi_name = self.new_roi_name_line_edit.text() # If the new ROI hasn't been drawn, draw the new ROI. Then if the new # ROI is drawn successfully, proceed to save the new ROI. if self.new_ROI_contours is None: if not self.onDrawButtonClicked(): return # Get a dict to convert SOPInstanceUID to slice id slice_ids_dict = get_dict_slice_to_uid(PatientDictContainer()) # Transform new_ROI_contours to a list of roi information rois_to_save = {} for uid, contour_sequence in self.new_ROI_contours.items(): slider_id = slice_ids_dict[uid] location = self.patient_dict_container.filepaths[slider_id] ds = pydicom.dcmread(location) slice_info = {'coords': contour_sequence, 'ds': ds} rois_to_save[slider_id] = slice_info roi_list = ROI.convert_hull_list_to_contours_data( rois_to_save, self.patient_dict_container) connectSaveROIProgress(self, roi_list, self.dataset_rtss, new_roi_name, self.roi_saved)
def cleanup(self): patient_dict_container = PatientDictContainer() patient_dict_container.clear() # Close 3d vtk widget self.three_dimension_view.close() self.cleanup_image_fusion() self.cleanup_pt_ct_viewer()
def test_save_radiomics_data(): """ Test for saving pyradiomics data to a DICOM SR file. """ # Get test data files # 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 patient_dict_container = PatientDictContainer() patient_dict_container.clear() patient_dict_container.set_initial_values(file_path, read_data_dict, file_names_dict) file_path = patient_dict_container.path file_path = Path(file_path).joinpath("PyRadiomics-SR.dcm") ds = patient_dict_container.dataset[0] dicom_sr = DICOMStructuredReport.generate_dicom_sr(file_path, ds, "text", "PYRADIOMICS") dicom_sr.save_as(file_path) # Assert that the new SR exists assert os.path.isfile(file_path) # Delete the created DICOM SR os.remove(file_path)
def test_create_roi(): rt_ss = dataset.Dataset() rt_ss.StructureSetROISequence = [] rt_ss.StructureSetROISequence.append(dataset.Dataset()) rt_ss.StructureSetROISequence[0].ReferencedFrameOfReferenceUID = "1.2.3" rt_ss.StructureSetROISequence[0].ROINumber = "1" rt_ss.ROIContourSequence = [] rt_ss.RTROIObservationsSequence = [] roi_name = "NewTestROI" roi_coordinates = [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0] # a closed right triangle image_ds = dataset.Dataset() image_ds.SOPClassUID = "1.2.840.10008.5.1.4.1.1.2" image_ds.SOPInstanceUID = "1.2.3.4.5.6.7.8.9" patient_dict_container = PatientDictContainer() # container has to be initialised with kwargs content for the get/set to not fail for lack of an # "additional_parameters" dict. patient_dict_container.set_initial_values(None, None, None, blah="blah", rois={}) if patient_dict_container.get("rois") is not None: print("rois are present in patient dict container") updated_rtss = create_roi(rt_ss, roi_name, roi_coordinates, image_ds) first_contour = updated_rtss.ROIContourSequence[0].ContourSequence[0] assert (first_contour.ContourImageSequence[0].ReferencedSOPClassUID == image_ds.SOPClassUID) assert (first_contour.ContourGeometricType == "CLOSED_PLANAR") assert (rt_ss.RTROIObservationsSequence[0].RTROIInterpretedType == "ORGAN")
def batch_iso2roi_handler(self, interrupt_flag, progress_callback, patient): """ Handles creating, starting, and processing the results of batch ISO2ROI. :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. :param patient: The patient to perform this process on. """ # Get current patient files cur_patient_files = \ BatchProcessingController.get_patient_files(patient) # Create and start process process = BatchProcessISO2ROI(progress_callback, interrupt_flag, cur_patient_files) success = process.start() # Add rtss to patient in case it is needed in future # processes if success: if PatientDictContainer().get("rtss_modified"): self.update_rtss(patient) reason = "SUCCESS" else: reason = process.summary # Append process summary if patient not in self.batch_summary[0].keys(): self.batch_summary[0][patient] = {} self.batch_summary[0][patient]["iso2roi"] = reason progress_callback.emit(("Completed ISO2ROI", 100))
def populate_table(self): """ Populates the table with data from the DICOM-SR file, if it exists. """ # Attempt to get clinical data dataset patient_dict_container = PatientDictContainer() try: clinical_data = patient_dict_container.dataset['sr-cd'] # Get text from clinical data dataset text = clinical_data.ContentSequence[0].TextValue # Split text into dictionary text_data = text.splitlines() for row in text_data: key, value = row.split(":") self.data_dict[key] = value except KeyError: # See if data has been imported if self.data_dict: pass else: return # Populate table with loaded values for i, key in enumerate(self.data_dict): attrib = QtWidgets.QTableWidgetItem(key) value = QtWidgets.QTableWidgetItem(self.data_dict[key]) self.table_cd.insertRow(i) self.table_cd.setItem(i, 0, attrib) self.table_cd.setItem(i, 1, value) self.table_populated = True
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 and set path variable path = Path.cwd().joinpath('test', 'testdata') files = get_dicom_files(path) # list of DICOM test files file_path = os.path.dirname(os.path.commonprefix(files)) read_data_dict, file_names_dict = ImageLoading.get_datasets(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 # This prevents crashes if "rtss" in file_names_dict: dataset_rtss = dcmread(file_names_dict['rtss']) self.rois = ImageLoading.get_roi_info(dataset_rtss) patient_dict_container.set("rois", self.rois) # Open the main window self.main_window = MainWindow() self.main_window.right_panel.setCurrentWidget( self.main_window.dicom_tree) self.dicom_tree = self.main_window.dicom_tree
def on_loaded_suv2roi(self): """ Called when progress bar has finished. Closes the progress window and refreshes the main screen. """ if self.suv2roi.suv2roi_status: patient_dict_container = PatientDictContainer() self.structures_tab.fixed_container_structure_modified(( patient_dict_container.get('dataset_rtss'), {"draw": None})) else: # Alert user that SUV2ROI failed and for what reason if self.suv2roi.failure_reason == "UNIT": failure_reason = \ "PET units are not Bq/mL. OnkoDICOM can currently only\n" \ "perform SUV2ROI on PET images stored in these units." elif self.suv2roi.failure_reason == "DECY": failure_reason = \ "PET is not decay corrected. OnkoDICOM can currently " \ "only\nperform SUV2ROI on PET images that are decay " \ "corrected." else: failure_reason = "The SUV2ROI process has failed." button_reply = \ QtWidgets.QMessageBox( QtWidgets.QMessageBox.Icon.Warning, "SUV2ROI Failed", failure_reason, QtWidgets.QMessageBox.StandardButton.Ok, self) button_reply.button( QtWidgets.QMessageBox.StandardButton.Ok).setStyleSheet( self.stylesheet) button_reply.exec_() # Close progress window self.suv2roi_progress_window.close()
def __init__(self): QtWidgets.QWidget.__init__(self) self.patient_dict_container = PatientDictContainer() self.rx_dose_in_cgray = self.patient_dict_container.get( "rx_dose_in_cgray") self.color_dict = self.init_color_isod() self.color_squares = self.init_color_squares() self.checkboxes = self.init_checkboxes() # Create and initialise ISO2ROI button and layout self.iso2roi_button = QtWidgets.QPushButton() self.iso2roi_button.setText("Convert Isodoses to ROIs") self.iso2roi_button.clicked.connect(self.iso2roi_button_clicked) self.iso2roi_layout = QtWidgets.QHBoxLayout() self.iso2roi_layout.setContentsMargins(0, 0, 0, 0) self.iso2roi_layout.addWidget(self.iso2roi_button) self.isodose_tab_layout = QtWidgets.QVBoxLayout() self.isodose_tab_layout.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignTop) self.isodose_tab_layout.setSpacing(0) self.init_layout() self.iso2roi = ISO2ROI() # Add button to tab self.isodose_tab_layout.addStretch() self.isodose_tab_layout.addLayout(self.iso2roi_layout) self.setLayout(self.isodose_tab_layout) self.progress_window = ProgressWindow( self, QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowCloseButtonHint) self.progress_window.signal_loaded.connect(self.on_loaded_iso2roi)
def save_rtss(cls): """ Saves the RT Struct. """ patient_dict_container = PatientDictContainer() rtss_directory = Path(patient_dict_container.get("file_rtss")) patient_dict_container.get("dataset_rtss").save_as(rtss_directory)
def save_clinical_data(self): """ Saves clinical data to a DICOM-SR file. Overwrites any existing clinical data SR files in the dataset. """ # Only save if there is at least one row in the table if self.table_cd.rowCount() <= 0: return # Create string from clinical data dictionary text = "" for key in self.data_dict: text += str(key) + ": " + str(self.data_dict[key]) + "\n" # Create and save DICOM SR file patient_dict_container = PatientDictContainer() file_path = patient_dict_container.path file_path = Path(file_path).joinpath("Clinical-Data-SR.dcm") ds = patient_dict_container.dataset[0] dicom_sr = DICOMStructuredReport.generate_dicom_sr( file_path, ds, text, "CLINICAL-DATA") dicom_sr.save_as(file_path) # Update patient dict container patient_dict_container.dataset['sr-cd'] = dicom_sr patient_dict_container.filepaths['sr-cd'] = file_path
def __init__(self, *args, **kwargs): super(CalculateDVHProgressWindow, self).__init__(*args, **kwargs) layout = QtWidgets.QVBoxLayout() text = QtWidgets.QLabel( "Calculating DVHs... (This may take several minutes)") layout.addWidget(text) self.setWindowTitle("Please wait...") self.setLayout(layout) self.threadpool = QtCore.QThreadPool() self.patient_dict_container = PatientDictContainer() dataset_rtss = self.patient_dict_container.dataset["rtss"] dataset_rtdose = self.patient_dict_container.dataset["rtdose"] rois = self.patient_dict_container.get("rois") dict_thickness = ImageLoading.get_thickness_dict( dataset_rtss, self.patient_dict_container.dataset) interrupt_flag = threading.Event() fork_safe_platforms = ['Linux'] if platform.system() in fork_safe_platforms: worker = Worker(ImageLoading.multi_calc_dvh, dataset_rtss, dataset_rtdose, rois, dict_thickness) else: worker = Worker(ImageLoading.calc_dvhs, dataset_rtss, dataset_rtdose, rois, dict_thickness, interrupt_flag) worker.signals.result.connect(self.dvh_calculated) self.threadpool.start(worker)
def __init__(self, roi_color=None, iso_color=None): QtWidgets.QWidget.__init__(self) self.patient_dict_container = PatientDictContainer() self.iso_color = iso_color self.zoom = 1 self.current_slice_number = None self.dicom_view_layout = QtWidgets.QHBoxLayout() # Create components self.slider = QtWidgets.QSlider(QtCore.Qt.Vertical) self.init_slider() self.view = QtWidgets.QGraphicsView() self.init_view() self.scene = QtWidgets.QGraphicsScene() # Set layout self.dicom_view_layout.addWidget(self.view) self.dicom_view_layout.addWidget(self.slider) self.setLayout(self.dicom_view_layout) # Init metadata widgets self.metadata_layout = QtWidgets.QVBoxLayout(self.view) self.label_image_id = QtWidgets.QLabel() self.label_image_pos = QtWidgets.QLabel() self.label_wl = QtWidgets.QLabel() self.label_image_size = QtWidgets.QLabel() self.label_zoom = QtWidgets.QLabel() self.label_patient_pos = QtWidgets.QLabel() self.init_metadata() self.update_view()
def __init__(self): QtWidgets.QWidget.__init__(self) self.patient_dict_container = PatientDictContainer() self.dvh_calculated = self.patient_dict_container.has_attribute( "raw_dvh") self.rt_dose = self.patient_dict_container.dataset['rtdose'] self.raw_dvh = None self.dvh_x_y = None self.plot = None self.selected_rois = self.patient_dict_container.get("selected_rois") self.dvh_tab_layout = QtWidgets.QVBoxLayout() try: # Import the DVH from RT Dose self.import_rtdose() except (AttributeError, KeyError): # Construct the layout based on whether or not the DVH has # already been calculated. # TODO: convert to logging print("DVH data not in RT Dose.") if self.dvh_calculated: self.init_layout_dvh() else: self.init_layout_no_dvh() self.setLayout(self.dvh_tab_layout)
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) # Create variables to be initialised later self.dicom_files = None self.suv_data = [] # Create SUV2ROI object self.suv2roi = SUV2ROI() # Set patient weight. Not actual weight, just for testing # purposes. self.suv2roi.patient_weight = 70000
def update_ui(self): # Instantiate a local new PatientDictContainer patient_dict_container = PatientDictContainer() patient = patient_dict_container.get("basic_info") # Compare local patient with previous instance of ImageFusion if self.patient_id != patient['id']: self.update_patient()
def update_patient(self): self.clear_checked_leaves() self.patient_dict_container = PatientDictContainer() self.patient = self.patient_dict_container.get("basic_info") self.patient_id = self.patient['id'] dataset = self.patient_dict_container.dataset[0] self.patient_current_image_series_uid = \ dataset.get("SeriesInstanceUID")
def update_ui(self, moving=False): """ Update the UI of Structure Tab when a new patient is opened """ self.patient_dict_container = PatientDictContainer() self.rois = self.patient_dict_container.get("rois") self.color_dict = self.init_color_roi(self.patient_dict_container) self.patient_dict_container.set("roi_color_dict", self.color_dict) if hasattr(self, "modified_indicator_widget"): self.modified_indicator_widget.setParent(None) self.update_content()
def get_fused_window(level, window): """ Apply windowing on the fixed and moving (linear-registered) images. Args: level(int): the level (midpoint) of windowing window(any): the window (range) of windowing Return: color_axial (QtGui.QPixmap): pixmap of the registered image from axial view color_sagittal (QtGui.QPixmap): pixmap of the registered image from sagittal view color_coronal (QtGui.QPixmap): pixmap of the registered image from coronal view tfm (sitk.CompositeTransform): transformation object containing data that is a product from linear_registration """ patient_dict_container = PatientDictContainer() old_images = patient_dict_container.get("sitk_original") fused_image = patient_dict_container.get("fused_images") tfm = fused_image[1] array = sitk.GetArrayFromImage(old_images).shape axial_slice_count = array[0] coronal_slice_count = array[1] sagittal_slice_count = array[1] sp_plane, _, sp_slice = old_images.GetSpacing() asp = (1.0 * sp_slice) / sp_plane color_axial = {} color_sagittal = {} color_coronal = {} windowing = (int(level - CT_RESCALE_INTERCEPT), int(window)) for i in range(axial_slice_count): color_axial[i] = \ get_fused_pixmap(old_images, fused_image[0], asp, i, "axial", windowing) for i in range(sagittal_slice_count): color_sagittal[i] = \ get_fused_pixmap(old_images, fused_image[0], asp, i, "sagittal", windowing) for i in range(coronal_slice_count): color_coronal[i] = \ get_fused_pixmap(old_images, fused_image[0], asp, i, "coronal", windowing) return color_axial, color_sagittal, color_coronal, tfm
def update_rtss(self, patient): """ Updates the patient dict container with the newly created RTSS (if a process generates one), so it can be used by future processes. :param patient: The patient with the newly-created RTSS. """ # Get new RTSS rtss = PatientDictContainer().dataset['rtss'] # Create a series and image from the RTSS rtss_series = Series(rtss.SeriesInstanceUID) rtss_series.series_description = rtss.get("SeriesDescription") rtss_image = Image(PatientDictContainer().filepaths['rtss'], rtss.SOPInstanceUID, rtss.SOPClassUID, rtss.Modality) rtss_series.add_image(rtss_image) # Add the new study to the patient patient.studies[rtss.StudyInstanceUID].add_series(rtss_series) # Update the patient dict container PatientDictContainer().set("rtss_modified", False)
def read_images_for_fusion(level=0, window=0): """ Performs initial image fusion, this is by converting the old and new images for transformations into SITK object. Images are co-registered using SITK library. Images and SITK.CompositeTransformation objects are added to the patient dataset. Args: level(int): midpoint of window window(Any): range of values, should at least contain low bound and high bound """ patient_dict_container = PatientDictContainer() moving_dict_container = MovingDictContainer() if level == 0 or window == 0: level = patient_dict_container.get("level") window = patient_dict_container.get("window") amount = len(patient_dict_container.filepaths) orig_fusion_list = [] for i in range(amount): try: orig_fusion_list.append(patient_dict_container.filepaths[i]) except KeyError: continue orig_image = sitk.ReadImage(orig_fusion_list) patient_dict_container.set("sitk_original", orig_image) amount = len(moving_dict_container.filepaths) new_fusion_list = [] for i in range(amount): try: new_fusion_list.append(moving_dict_container.filepaths[i]) except KeyError: continue new_image = sitk.ReadImage(new_fusion_list) moving_dict_container.set("sitk_moving", new_image) create_fused_model(orig_image, new_image) color_axial, color_sagittal, color_coronal, tfm = \ get_fused_window(level, window) patient_dict_container.set("color_axial", color_axial) patient_dict_container.set("color_sagittal", color_sagittal) patient_dict_container.set("color_coronal", color_coronal) moving_dict_container.set("tfm", tfm)
def __init__(self): QtWidgets.QWidget.__init__(self) self.patient_dict_container = PatientDictContainer() self.rx_dose_in_cgray = self.patient_dict_container.get("rx_dose_in_cgray") self.color_dict = self.init_color_isod() self.color_squares = self.init_color_squares() self.checkboxes = self.init_checkboxes() self.isodose_tab_layout = QtWidgets.QVBoxLayout() self.isodose_tab_layout.setAlignment(QtCore.Qt.AlignTop) self.isodose_tab_layout.setSpacing(0) self.init_layout() self.setLayout(self.isodose_tab_layout)
def perform_suv2roi(self): """ Performs the SUV2ROI process. """ # Get patient weight - needs to run first as GUI cannot run in # threads, like the ProgressBar patient_dict_container = PatientDictContainer() dataset = patient_dict_container.dataset[0] self.suv2roi.get_patient_weight(dataset) if self.suv2roi.patient_weight is None: return # Start the SUV2ROI process self.suv2roi_progress_window.start(self.suv2roi.start_conversion)
def __init__(self, action_handler: ActionHandler): QToolBar.__init__(self) self.action_handler = action_handler self.patient_dict_container = PatientDictContainer() self.setCursor(QCursor(Qt.PointingHandCursor)) self.setMovable(False) self.setFloatable(False) self.setContextMenuPolicy(Qt.PreventContextMenu) # Drop-down list for Windowing button on toolbar self.button_windowing = QToolButton() self.button_windowing.setMenu(self.action_handler.menu_windowing) self.button_windowing.setPopupMode(QToolButton.InstantPopup) self.button_windowing.setIcon(self.action_handler.icon_windowing) # Drop-down list for Export button on toolbar self.button_export = QToolButton() self.button_export.setMenu(self.action_handler.menu_export) self.button_export.setPopupMode(QToolButton.InstantPopup) self.button_export.setIcon(self.action_handler.icon_export) # Spacer for the toolbar spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) spacer.setFocusPolicy(Qt.NoFocus) # Add actions to toolbar self.addAction(self.action_handler.action_open) self.addSeparator() self.addAction(self.action_handler.action_zoom_out) self.addAction(self.action_handler.action_zoom_in) self.addSeparator() self.addWidget(self.button_windowing) self.addSeparator() self.addAction(self.action_handler.action_transect) self.addSeparator() self.addAction(self.action_handler.action_one_view) self.addAction(self.action_handler.action_four_views) self.addAction(self.action_handler.action_show_cut_lines) self.addSeparator() self.addAction(self.action_handler.action_image_fusion) self.addSeparator() self.addAction(self.action_handler.action_add_ons) self.addWidget(spacer) self.addWidget(self.button_export) self.addAction(self.action_handler.action_save_as_anonymous) if self.patient_dict_container.has_modality('rtss'): self.addAction(self.action_handler.action_save_structure)
def __init__(self): self.dvh_data = None # Load test DICOM files desired_path = Path.cwd().joinpath('test', 'testdata') selected_files = find_DICOM_files(desired_path) 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)
def create_fused_model(old_images, new_image): """ Performs the image fusion and stores fusion information. Args: old_images(sitk): Image set from Primary/Fixed Image new_image(sitk): Image set from the Secondary/Moving Image """ patient_dict_container = PatientDictContainer() fused_image = register_images(old_images, new_image) patient_dict_container.set("fused_images", fused_image) if fused_image[2]: combined_affine = convert_composite_to_affine_transform(fused_image[1]) affine_matrix = convert_combined_affine_to_matrix(combined_affine) write_transform_to_dcm(affine_matrix)
def create_new_rtstruct(cls, progress_callback): """ Generates a new RTSS and edits the patient dict container. Used for batch processing. """ # Get common directory patient_dict_container = PatientDictContainer() file_path = patient_dict_container.filepaths.values() file_path = Path(os.path.commonpath(file_path)) # Get new RT Struct file path file_path = str(file_path.joinpath("rtss.dcm")) # Create RT Struct file progress_callback.emit(("Generating RT Structure Set", 60)) ct_uid_list = ImageLoading.get_image_uid_list( patient_dict_container.dataset) ds = ROI.create_initial_rtss_from_ct(patient_dict_container.dataset[0], file_path, ct_uid_list) ds.save_as(file_path) # Add RT Struct file path to patient dict container patient_dict_container.filepaths['rtss'] = file_path filepaths = patient_dict_container.filepaths # Add RT Struct dataset to patient dict container patient_dict_container.dataset['rtss'] = ds dataset = patient_dict_container.dataset # Set some patient dict container attributes patient_dict_container.set("file_rtss", filepaths['rtss']) patient_dict_container.set("dataset_rtss", dataset['rtss']) dicom_tree_rtss = DicomTree(filepaths['rtss']) patient_dict_container.set("dict_dicom_tree_rtss", dicom_tree_rtss.dict) dict_pixluts = ImageLoading.get_pixluts(patient_dict_container.dataset) patient_dict_container.set("pixluts", dict_pixluts) rois = ImageLoading.get_roi_info(ds) patient_dict_container.set("rois", rois) patient_dict_container.set("selected_rois", []) patient_dict_container.set("dict_polygons_axial", {}) patient_dict_container.set("rtss_modified", True)
def dvh2rtdose(dict_dvh): """ Export dvh data to RT DOSE file. :param dict_dvh: A dictionary of DVH {ROINumber: DVH} :param patient_id: Patient Identifier """ # Create DVH sequence dvh_sequence = Sequence([]) # Add DVHs to the sequence for ds in dict_dvh: # Create new DVH dataset new_ds = Dataset() # Add attributes new_ds.add_new(Tag("DVHType"), "CS", dict_dvh[ds].dvh_type.upper()) new_ds.add_new(Tag("DoseUnits"), "CS", dict_dvh[ds].dose_units.upper()) new_ds.add_new(Tag("DoseType"), "CS", "PHYSICAL") new_ds.add_new(Tag("DVHDoseScaling"), "DS", "1.0") new_ds.add_new(Tag("DVHVolumeUnits"), "CS", dict_dvh[ds].volume_units.upper()) new_ds.add_new(Tag("DVHNumberOfBins"), "IS", len(dict_dvh[ds].bins)) # Calculate and add DVH data dvh_data = [] for i in range(len(dict_dvh[ds].counts)): dvh_data.append(str(dict_dvh[ds].bins[1])) dvh_data.append(str(dict_dvh[ds].counts[i])) new_ds.add_new(Tag("DVHData"), "DS", dvh_data) # Reference ROI sequence dataset/sequence referenced_roi_sequence = Dataset() referenced_roi_sequence.add_new(Tag("DVHROIContributionType"), "CS", "INCLUDED") referenced_roi_sequence.add_new(Tag("ReferencedROINumber"), "IS", ds) new_ds.add_new(Tag("DVHReferencedROISequence"), "SQ", Sequence([referenced_roi_sequence])) # Add new DVH dataset to DVH sequences dvh_sequence.append(new_ds) # Save new RT DOSE patient_dict_container = PatientDictContainer() patient_dict_container.dataset['rtdose'].DVHSequence = dvh_sequence path = patient_dict_container.filepaths['rtdose'] patient_dict_container.dataset['rtdose'].save_as(path)