def test_parse_dicom_folder(dicom_folder): # given p_kernel = PyPlanScoringKernel() # when having a folder containing RS/RD/RP dicom # then p_kernel.parse_dicom_folder(dicom_folder) assert p_kernel.dcm_files
def test_parse_empty_dicom_folder(tmpdir): # given p_kernel = PyPlanScoringKernel() # when having a folder containing RS/RD/RP dicom # then with pytest.raises(FileNotFoundError): p_kernel.parse_dicom_folder(tmpdir)
def test_setup_case(dicom_folder): # given case files rs_dvh = os.path.join(dicom_folder, 'RS.dcm') file_path = os.path.join(dicom_folder, 'Scoring_criteria_2018.xlsx') case_name = 'BiLateralLungSBRTCase' # when instantiate p_kernel = PyPlanScoringKernel() p_kernel.setup_case(rs_dvh, file_path, case_name) assert p_kernel.case is not None
def __init__(self, parent=None): super(MainDialog, self).__init__(parent=parent) self.setupUi(self) self.folder_root = None self.result = None # calculation kernel self.calc_kernel = PyPlanScoringKernel() # Redirect STD out to stdout = OutputWrapper(self, True) stdout.outputWritten.connect(self.handle_output) stderr = OutputWrapper(self, False) stderr.outputWritten.connect(self.handle_output) self.worker = Worker() # connect Signal and Slots self.set_conections() self.save_reports_button.setEnabled(False) self.textBrowser.setOpenExternalLinks(True)
def test_setup_dvh_calculation(dicom_folder, ini_file_path): # given case files rs_dvh = os.path.join(dicom_folder, 'RS.dcm') file_path = os.path.join(dicom_folder, 'Scoring_criteria_2018.xlsx') case_name = 'BiLateralLungSBRTCase' # when instantiate p_kernel = PyPlanScoringKernel() # if not setup case before setup dvh calculator p_kernel.setup_dvh_calculation(ini_file_path) # then assert p_kernel.dvh_calculator is None # when setup case p_kernel = PyPlanScoringKernel() p_kernel.setup_case(rs_dvh, file_path, case_name) p_kernel.setup_dvh_calculation(ini_file_path) # then assert p_kernel.dvh_calculator is not None
def test_calculate_dvh(dicom_folder, ini_file_path): # given case files rs_dvh = os.path.join(dicom_folder, 'RS.dcm') file_path = os.path.join(dicom_folder, 'Scoring_criteria_2018.xlsx') case_name = 'BiLateralLungSBRTCase' # when instantiate p_kernel = PyPlanScoringKernel() p_kernel.parse_dicom_folder(dicom_folder) p_kernel.setup_case(rs_dvh, file_path, case_name) p_kernel.setup_dvh_calculation(ini_file_path) p_kernel.setup_planing_item() p_kernel.calculate_dvh() assert p_kernel.dvh_data
def test_calc_plan_complexity(test_case, dicom_folder, ini_file_path): # given case files rs_dvh = os.path.join(dicom_folder, 'RS.dcm') file_path = os.path.join(dicom_folder, 'Scoring_criteria_2018.xlsx') case_name = 'BiLateralLungSBRTCase' # when instantiate p_kernel = PyPlanScoringKernel() p_kernel.parse_dicom_folder(dicom_folder) p_kernel.setup_case(rs_dvh, file_path, case_name) p_kernel.setup_dvh_calculation(ini_file_path) p_kernel.setup_planing_item() # calculate plan complexity p_kernel.calc_plan_complexity() test_case.assertAlmostEqual(p_kernel.plan_complexity, 0.166503597706, places=3)
def test_calc_plan_score(dicom_folder, ini_file_path): # given case files rs_dvh = os.path.join(dicom_folder, 'RS.dcm') file_path = os.path.join(dicom_folder, 'Scoring_criteria_2018.xlsx') case_name = 'BiLateralLungSBRTCase' # when instantiate p_kernel = PyPlanScoringKernel() p_kernel.parse_dicom_folder(dicom_folder) p_kernel.setup_case(rs_dvh, file_path, case_name) p_kernel.setup_dvh_calculation(ini_file_path) p_kernel.setup_planing_item() p_kernel.calculate_dvh() p_kernel.calc_plan_score() assert not p_kernel._report_data_frame.empty assert round(p_kernel._total_score) == round(90.01) # save report data p_kernel.save_report_data()
class MainDialog(QtGui.QMainWindow, PyPlanScoringBrainPTV.Ui_MainWindow): def __init__(self, parent=None): super(MainDialog, self).__init__(parent=parent) self.setupUi(self) self.folder_root = None self.result = None # calculation kernel self.calc_kernel = PyPlanScoringKernel() # Redirect STD out to stdout = OutputWrapper(self, True) stdout.outputWritten.connect(self.handle_output) stderr = OutputWrapper(self, False) stderr.outputWritten.connect(self.handle_output) self.worker = Worker() # connect Signal and Slots self.set_conections() self.save_reports_button.setEnabled(False) self.textBrowser.setOpenExternalLinks(True) def handle_output(self, text, stdout): # self.listWidget.addItem(text) self.textBrowser.insertPlainText(str(text)) def set_conections(self): self.action_developer.triggered.connect(self.about) self.import_button.clicked.connect(self.on_import) self.save_reports_button.clicked.connect(self.on_save) self.worker.worker_finished.connect(self.worker_done) def worker_done(self, obj): self.calc_kernel = obj self.calc_kernel.save_dvh_data(self.name) self.calc_kernel.save_report_data(self.name) total_score = self.calc_kernel.total_score self.textBrowser.insertPlainText('Total score: %1.2f \n' % total_score) self.textBrowser.insertPlainText('---------- Metrics -------------\n') # Pretty print print(self.calc_kernel.report) print() if self.complexity_check_box.isChecked(): self.textBrowser.insertPlainText( '---------- Complexity metric -------------\n') # try: self.calc_kernel.calc_plan_complexity() self.calc_kernel.save_complexity_figure_per_beam() self.textBrowser.insertPlainText( "Aperture complexity: %1.3f [mm-1]:\n" % self.calc_kernel.plan_complexity) txt = 'It is a Python 3.x port of the Eclipse ESAPI plug-in script.\n' \ 'As such, it aims to contain the complete functionality of the aperture complexity analysis\n' self.textBrowser.insertPlainText(txt) self.textBrowser.insertPlainText("Reference: ") self.textBrowser.insertHtml( "<a href=\"https://github.com/umro/Complexity\" > https://github.com/umro/Complexity</a>" ) self.textBrowser.insertPlainText('\n') # except: # print("Aperture complexity is valid only in linac-based dynamic treatments - (IMRT/VMAT)") def setup_case(self, file_path, case_name, ini_file_path, rs_dvh=''): if not rs_dvh: rs_dvh = self.calc_kernel.dcm_files[ 'rtss'] # TODO add folder DVH file self.calc_kernel.setup_case(rs_dvh, file_path, case_name) self.calc_kernel.setup_dvh_calculation(ini_file_path) self.calc_kernel.setup_planing_item() def on_import(self): self.textBrowser.clear() self.name = self.lineEdit.text() if self.name: self.folder_root = QtGui.QFileDialog.getExistingDirectory( self, "Select the directory containing only: RP and RD Dicom RT dose files from one plan", QtCore.QDir.currentPath()) if self.folder_root: dcm_files, flag = self.calc_kernel.parse_dicom_folder( self.folder_root) if flag: # setup case using global variables self.setup_case(criteria_file, case_name, ini_file_path, rs_dvh) self.worker.set_calc_kernel(self.calc_kernel) self.textBrowser.insertPlainText( 'Loaded - DICOM-RT Files: \n') txt = [os.path.split(v)[1] for k, v in dcm_files.items()] for t in txt: self.textBrowser.insertPlainText(str(t) + '\n') self.save_reports_button.setEnabled(True) else: msg = "<p>missing Dicom Files: " + str(dcm_files) QtGui.QMessageBox.critical(self, "Missing Data", msg, QtGui.QMessageBox.Abort) else: msg = "Please set the output file name" QtGui.QMessageBox.critical(self, "Missing Data", msg, QtGui.QMessageBox.Abort) def on_save(self): self.textBrowser.insertPlainText( '------------- Calculating DVH and score --------------\n') self.worker.start() def about(self): txt = "PyPlanScoring - 2018 - RT Plan Competition: %s \n" \ "Be the strongest link in the radiotherapy chain\n" \ "https://radiationknowledge.org \n" \ "Author: %s\n" \ "Copyright (C) 2017 - 2018 Victor Gabriel Leandro Alves, All rights reserved\n" \ "Platform details: Python %s on %s\n" \ "This program aims to calculate_integrate an approximate score.\n" \ "your final score may be different due to structure boundaries and dose interpolation uncertainties\n" \ "%s" \ % (__version__, __author__, platform.python_version(), platform.system(), __license__) QtGui.QMessageBox.about(self, 'Information', txt)