def get_dicom_data(root_path: str) -> Dict[str, List[str]]: """ Provide all participant required files (RP,RS an RD DICOM FILES) :param root_path: participant folder :return: Pandas DataFrame containing path to files """ files = [ os.path.join(root, name) for root, dirs, files in os.walk(root_path) for name in files if name.endswith(('.dcm', '.DCM')) ] filtered_files = [] for f in files: obj = PyDicomParser(filename=f) rt_type = obj.GetSOPClassUID() # fix halcyon SOP class UI if rt_type is None: rt_type = obj.ds.Modality.lower() if rt_type in ['rtdose', 'rtplan', 'rtss']: filtered_files.append([rt_type, f]) # filter rtdose rd_files = [d[1] for d in filtered_files if d[0] == 'rtdose'] rp_files = [d[1] for d in filtered_files if d[0] == 'rtplan'] rs_files = [d[1] for d in filtered_files if d[0] == 'rtss'] dcm_files = {'rtdose': rd_files, 'rtplan': rp_files, 'rtss': rs_files} return dcm_files
def py_planning_item(): plan_dict = PyDicomParser(filename=rp).GetPlan() rs_dvh = os.path.join(DATA_DIR, 'RS_dvh.dcm') structures_tmp1 = PyDicomParser(filename=rs_dvh).GetStructures() criteria1 = pd.read_excel(file_path, sheet_name='calc_dvh') rt_case_tmp = RTCase("H&N", 123, structures_tmp1, criteria1) dose_values = PyDicomParser(filename=rd).get_dose_matrix() grid = PyDicomParser(filename=rd).get_grid_3d() dose = Dose3D(dose_values, grid, pq.Gy) dvh_calc = DVHCalculator(rt_case_tmp, calculation_options) return PyPlanningItem(plan_dict, rt_case_tmp, dose, dvh_calc)
def test_dvh_comparisson(setup_calculation_options): # Given plan DVH folder = os.path.join(DATA_DIR, 'lungSBRT') # parse DICOM folder # plan_folder = r'C:\Users\Victor\Dropbox\Plan_Competition_Project\tests\tests_data\pinnacle\plan1' plan_folder = r'C:\Users\Victor\Dropbox\Plan_Competition_Project\tests\tests_data\pinnacle\plan2' dcm_files, flag = get_participant_folder_data(plan_folder) rs_dvh = os.path.join(folder, 'RS.dcm') plan_dict = PyDicomParser(filename=dcm_files['rtplan']).GetPlan() # structures = PyDicomParser(filename=dcm_files['rtss']).GetStructures() structures = PyDicomParser(filename=rs_dvh).GetStructures() rd_dcm = PyDicomParser(filename=dcm_files['rtdose']) dose = rd_dcm.get_dose_3d() # criteria file file_path = os.path.join(folder, 'Scoring_criteria.xlsx') criteria = pd.read_excel(file_path, sheet_name='BiLateralLungSBRTCase') # setup RT case rt_case_tmp = RTCase("SBRT", 123, structures, criteria) dvh_calc = DVHCalculator(rt_case_tmp, setup_calculation_options) # when calculate DVH using pyplanScoring planning_obj = PyPlanningItem(plan_dict, rt_case_tmp, dose, dvh_calc) planning_obj.calculate_dvh() # for k, v in planning_obj.dvh_data.items(): # plot_dvh(v, v['name']) # plt.show() # # Calculating the score plan_eval = PlanEvaluation() plan_eval.criteria = criteria df = plan_eval.eval_plan(planning_obj) raw_score = df['Raw score'].sum() pass
def setup_planing_item(self): if self.dcm_files is not None and self.case is not None: if self.dvh_calculator is not None: # TODO refactor this into abstractions plan_dcm = PyDicomParser(filename=self.dcm_files['rtplan']) dose_dcm = PyDicomParser(filename=self.dcm_files['rtdose']) plan_dict = plan_dcm.GetPlan() dose_3d = dose_dcm.get_dose_3d() self._planning_item = PyPlanningItem(plan_dict, self.case, dose_3d, self.dvh_calculator)
def setup_planing_item(self): if self.dcm_files is not None and self.case is not None: if self.dvh_calculator is not None: # TODO refactor this into abstractions plan_dict = {} if self.dcm_files['rtdose']: dcm_objs = [ PyDicomParser(filename=f) for f in self.dcm_files['rtdose'] ] if len(dcm_objs) == 1: dose_3d = dcm_objs[0].get_dose_3d() else: # add 3D doses doses_3d = [obj.get_dose_3d() for obj in dcm_objs] # Sum DVHs acc = DoseAccumulation(doses_3d) dose_3d = acc.get_plan_sum() self._planning_item = PyPlanningItem( plan_dict, self.case, dose_3d, self.dvh_calculator)
def test_gk_dvh(): # Given slicer_dvh_file = r'C:\Users\Victor\Dropbox\Plan_Competition_Project\tests\tests_data\gk_plan\SLICER_RT_DVH.csv' plan_folder = r'C:\Users\Victor\Dropbox\Plan_Competition_Project\tests\tests_data\gk_plan' slicer_dvh = read_slicer_dvh(slicer_dvh_file) # strip columns names slicer_dvh.columns = [ 'Skull Value', 'CerebelarDir', 'FrontalEsq ', 'Tumor', 'Tumor 2', 'Tumor 3', 'Tumor 4', 'Tumor 5' ] dcm_files, flag = get_participant_folder_data(plan_folder) plan_dict = PyDicomParser(filename=dcm_files['rtplan']).GetPlan() structures = PyDicomParser(filename=dcm_files['rtss']).GetStructures() rd_dcm = PyDicomParser(filename=dcm_files['rtdose']) dose = rd_dcm.get_dose_3d() structures_py = [ PyStructure(s, end_cap=s['thickness'] / 2) for k, s in structures.items() ] grid = (0.1, 0.1, 0.1) dvh_pyplan = {} for s in structures_py[:-1]: dvh_calci = DVHCalculation(s, dose, calc_grid=grid) dvh_l = dvh_calci.calculate(verbose=True) dvh_pyplan[dvh_l['name']] = dvh_l # plot_dvh(dvh_l, dvh_l['name']) for target_name, dvh_calc in dvh_pyplan.items(): dose_t5 = slicer_dvh.index t5 = slicer_dvh.loc[:, target_name].values x_calc = np.arange(len(dvh_calc['data'])) * float(dvh_calc['scaling']) py_t5 = dvh_calc['data'] plt.plot(dose_t5, t5, label='Slicer-RT') plt.plot(x_calc, py_t5, label='PyPlanScoring') plt.title(target_name) plt.legend() plt.show()
if __name__ == '__main__': # Given # planIQ dvh dvh_ref_path = '/home/victor/Dropbox/Plan_Competition_Project/tests/tests_data/ptv_based_SRS/PTV Based - PlanIQ DVH - Eclipse VMAT - Body included - Ahmad March 24.txt' plan_iq_dvh = read_planiq_dvh(dvh_ref_path) # compare against SLICER DV plan_folder = r'/home/victor/Dropbox/Plan_Competition_Project/tests/tests_data/ptv_based_SRS' # dcm_files, flag = get_participant_folder_data(plan_folder) rtss = r'/home/victor/Dropbox/Plan_Competition_Project/tests/tests_data/ptv_based_SRS/RS.1.2.246.352.205.5644208623194161296.369175407993399980.dcm' rt_dose = '/home/victor/Dropbox/Plan_Competition_Project/tests/tests_data/ptv_based_SRS/RD.1.2.246.352.71.7.584747638204.1898898.20180324182516.dcm' ini_file = '/home/victor/Dropbox/Plan_Competition_Project/gui/cases/BrainMetSRSCase/PyPlanScoring.ini' setup_calculation_options = get_calculation_options(ini_file) structures = PyDicomParser(filename=rtss).GetStructures() rd_dcm = PyDicomParser(filename=rt_dose) dose = rd_dcm.get_dose_3d() plan_dict = {} # criteria file file_path = '/home/victor/Dropbox/Plan_Competition_Project/tests/tests_data/ptv_based_SRS/Scoring_criteria.xlsx' criteria = pd.read_excel(file_path, sheet_name='BrainSRS') # setup RT case rt_case_tmp = RTCase("SRS", 123, structures, criteria) dvh_calc = DVHCalculator(rt_case_tmp, setup_calculation_options) # when calculate DVH using pyplanScoring planning_obj = PyPlanningItem(plan_dict, rt_case_tmp, dose, dvh_calc) planning_obj.calculate_dvh()
def test_lung_case_dvh(setup_calculation_options): # Given plan DVH folder = os.path.join(DATA_DIR, 'lungSBRT') # DVH reference dvh_ref_path = os.path.join(folder, 'PlanIQ DVH - Ahmad Plan - March 12.txt') plan_dvh = read_planiq_dvh(dvh_ref_path) # parse DICOM folder rp = os.path.join(folder, 'RP.dcm') rs_dvh = os.path.join(folder, 'RS.dcm') rd = os.path.join(folder, 'RD.dcm') plan_dict = PyDicomParser(filename=rp).GetPlan() structures = PyDicomParser(filename=rs_dvh).GetStructures() dose_values = PyDicomParser(filename=rd).get_dose_matrix() grid = PyDicomParser(filename=rd).get_grid_3d() dose = Dose3D(dose_values, grid, pq.Gy) # criteria file file_path = os.path.join(folder, 'Scoring_criteria.xlsx') criteria = pd.read_excel(file_path, sheet_name='BiLateralLungSBRTCase') # setup RT case rt_case_tmp = RTCase("SBRT", 123, structures, criteria) dvh_calc = DVHCalculator(rt_case_tmp, setup_calculation_options) # when calculate DVH using pyplanScoring planning_obj = PyPlanningItem(plan_dict, rt_case_tmp, dose, dvh_calc) planning_obj.calculate_dvh() # compare against PLANIQ for roi_number, dvh in planning_obj.dvh_data.items(): name = dvh['name'] plot_dvh_comp(dvh, plan_dvh, name, folder) # plt.show() # compare clinical DVH data # dvhs = PyDicomParser(filename=rd).GetDVHs() # compare against Eclipse DVH dvh_calculated = planning_obj.dvh_data res = {} res_eclipse = {} for roi_number in dvhs.keys(): if roi_number in dvh_calculated: dvh_calc = dvh_calculated[roi_number] planiq_dvh = plan_dvh[structures[roi_number]['name']] x_calc = np.arange(len(dvh_calc['data'])) * float( dvh_calc['scaling']) x_planiq = plan_dvh.index cmp = CurveCompare(x_planiq, planiq_dvh, x_calc, dvh_calc['data']) # cmp.plot_results("PlanIQ", "PyPlanScoring", structures[roi_number]['name']) # plt.show() res[structures[roi_number]['name']] = cmp.stats_paper # Eclipse eclipse_dvh = dvhs[roi_number] x_eclipse = np.arange(len(eclipse_dvh['data'])) * float( eclipse_dvh['scaling']) cmp1 = CurveCompare(x_eclipse, eclipse_dvh['data'], x_calc, dvh_calc['data']) # cmp.plot_results("PlanIQ", "PyPlanScoring", structures[roi_number]['name']) res_eclipse[structures[roi_number]['name']] = cmp1.stats_paper res_plan_iq = pd.DataFrame.from_dict(res) res_plan_iq.to_csv(os.path.join(folder, "PyPlanScoringXPlanIQ.csv")) res_eclipsedf = pd.DataFrame.from_dict(res_eclipse) res_eclipsedf.to_csv(os.path.join(folder, "PyPlanScoringXEclipse.csv")) piq = [ res_plan_iq.min().min(), res_plan_iq.max().max(), res_plan_iq.mean().mean() ] ecl = [ res_eclipsedf.min().min(), res_eclipsedf.max().max(), res_eclipsedf.mean().mean() ] # # # then Get dvh data and compare with plan_data # for roi_number, dvh in planning_obj.dvh_data.items(): # name = dvh['name'] # plot_dvh_comp(dvh, plan_dvh, name, folder) # # plt.show() # # # compare it abainst eclipse data # # compare with TPS DVH dvhs = PyDicomParser(filename=rd).GetDVHs() # compare against Eclipse DVH dvh_calculated = planning_obj.dvh_data for roi_number in dvhs.keys(): if roi_number in dvh_calculated: plot_dvh_comp1(dvh_calculated[roi_number], dvhs[roi_number], structures[roi_number]['name'], folder) # plt.show() # # lung SBRT case # # # Calculating the score plan_eval = PlanEvaluation() plan_eval.criteria = criteria df = plan_eval.eval_plan(planning_obj) assert df['Raw score'].sum() == 88.612
# GETTING dvh DATA FROM DOSE import os import numpy as np from pyplanscoring.constraints.metrics import PlanningItem from pyplanscoring.core.dicom_reader import PyDicomParser from pyplanscoring.core.types import DoseUnit, DoseValuePresentation, VolumePresentation, DoseValue from tests.conftest import DATA_DIR, rp # given rd_dvh = os.path.join(DATA_DIR, 'RD_dvh.dcm') rs_dvh = os.path.join(DATA_DIR, 'RS_dvh.dcm') planning_item = PlanningItem(PyDicomParser(filename=rp), PyDicomParser(filename=rs_dvh), PyDicomParser(filename=rd_dvh)) def test_planning_item_general_info(test_case): ap = planning_item.approval_status test_case.assertEqual(ap, "UNAPPROVED") a_dt = planning_item.creation_date_time assert a_dt == '20171128' assert planning_item.plan assert planning_item.dose_data # test property beams assert len(planning_item.beams) > 0 assert planning_item.dose_value_presentation == 1 test_case.assertAlmostEqual(planning_item.total_prescribed_dose.value, 70.0)
return filtered_files if __name__ == '__main__': # slicer/RT DVH file_path = r'/home/victor/Dropbox/Plan_Competition_Project/tests/tests_data/left_chest_wall/photon_electron/Absolute DVH Photon and electron plan sum.txt' eclipse_dvh = read_eclipse_dvh(file_path) # path to dicom files folder = '/home/victor/Dropbox/Plan_Competition_Project/tests/tests_data/left_chest_wall/photon_electron' dicom_data = get_dicom_data(folder) # filter rtdose rd_files = [d[1] for d in dicom_data if d[0] == 'rtdose'] dcm_objs = [PyDicomParser(filename=rd_file) for rd_file in rd_files] doses_3d = [obj.get_dose_3d() for obj in dcm_objs] # Sum DVHs acc = DoseAccumulation(doses_3d) plan_sum = acc.get_plan_sum() # TODO compare with slicerRT plan sum DVH rs_file = '/home/victor/Dropbox/Plan_Competition_Project/tests/tests_data/left_chest_wall/photon_electron/RS.1.2.246.352.71.4.584747638204.283643.20180405155645.dcm' structures = PyDicomParser(filename=rs_file).GetStructures() structures_py = [ PyStructure(s, end_cap=s['thickness']) for k, s in structures.items() ] dvh_pyplan = {}
def setup_case(self, rs_file_path, file_path, sheet_name): structures = PyDicomParser(filename=rs_file_path).GetStructures() self._plan_eval.read(file_path, sheet_name=sheet_name) # todo implement setup case by id self._case = RTCase(sheet_name, 1, structures, self._plan_eval.criteria)
def rd_dcm(): """ Fixture to return DICOM-RTDOSE obj :return: """ return PyDicomParser(filename=rd)
rs = os.path.join(DATA_DIR, 'RS.dcm') rd = os.path.join(DATA_DIR, 'RD.dcm') rp = os.path.join(DATA_DIR, 'RP.dcm') str_names = [ 'LENS LT', 'PAROTID LT', 'BRACHIAL PLEXUS', 'OPTIC N. RT PRV', 'OPTIC CHIASM PRV', 'OPTIC N. RT', 'ORAL CAVITY', 'BRAINSTEM', 'SPINAL CORD', 'OPTIC CHIASM', 'LENS RT', 'LARYNX', 'SPINAL CORD PRV', 'EYE LT', 'PTV56', 'BRAINSTEM PRV', 'PTV70', 'OPTIC N. LT PRV', 'EYE RT', 'PTV63', 'OPTIC N. LT', 'LIPS', 'ESOPHAGUS', 'PTV70' ] rs_dvh = os.path.join(DATA_DIR, 'RS_dvh.dcm') structures_tmp = PyDicomParser(filename=rs_dvh).GetStructures() to_index = {v['name']: k for k, v in structures_tmp.items()} # fixtures @pytest.fixture(scope="session") def rp_dcm(): """ Fixture to return DICOM-RTPLAN obj :return: """ return PyDicomParser(filename=rp) @pytest.fixture(scope="session") def rs_dcm():
def rs_dcm(): """ Fixture to return DICOM-RTSTRUCT obj :return: """ return PyDicomParser(filename=rs)
def rp_dcm(): """ Fixture to return DICOM-RTPLAN obj :return: """ return PyDicomParser(filename=rp)
def dvh1(): rd_dvh = os.path.join(DATA_DIR, 'RD_dvh.dcm') dvh_all = PyDicomParser(filename=rd_dvh).GetDVHs() return DVHData(dvh_all[61])
def dvh_calculator(): rs_dvh = os.path.join(DATA_DIR, 'RS_dvh.dcm') structures_tmp1 = PyDicomParser(filename=rs_dvh).GetStructures() rt_case_tmp = RTCase("H&N", 123, structures_tmp1, criteria) return DVHCalculator(rt_case_tmp, calculation_options)
def dose_3d(): dose_values = PyDicomParser(filename=rd).get_dose_matrix() grid = PyDicomParser(filename=rd).get_grid_3d() return Dose3D(dose_values, grid, pq.Gy)