Ejemplo n.º 1
0
    def single_calc_dvhs(self,
                         rtss,
                         rtdose,
                         dict_roi,
                         callback,
                         dose_limit=None):
        dict_dvh = {}
        roi_list = []
        for key in dict_roi:
            roi_list.append(key)
            self.copied += len(roi_list)
            callback(self.copied)  # update the bar

        for roi in roi_list:
            dict_dvh[roi] = dvhcalc.get_dvh(rtss, rtdose, roi, dose_limit)
            self.copied += len(roi_list)
            callback(self.copied)  # update the bar

        return dict_dvh
Ejemplo n.º 2
0
 def test_FF_decubitus_right_structure_extents(self):
     """Test DVH for FF decubitus Rt orientation using structure extents."""
     self.dose.ImageOrientationPatient = [0, -1, 0, -1, 0, 0]
     self.dose.PixelSpacing = [2.0, 1.0]  # between Rows, Columns
     self.dose.ImagePositionPatient = [14, 19, 20]  # X Y Z top left
     # see grid from test_FF_decubitus_right
     #                          14 15 16       19             24
     expected_counts = [0] * 14 + [
         1, 1, 0, 1, 2, 1, 0, 0, 0, 0, 1, 1, 0, 1, 2, 1, 0, 0, 0, 0, 1, 1,
         0, 1, 2, 1
     ]
     #                                               34
     dvh = get_dvh(self.ss, self.dose, 1, use_structure_extents=True)
     diffl = dvh.differential
     # Counts are normalized to total, and to volume,
     # So undo that here for test dose grid.
     # 18=num dose voxels inside struct; 0.36=volume
     got_counts = diffl.counts * 18 / 0.36
     assert_allclose(got_counts, expected_counts)
Ejemplo n.º 3
0
def calc_dvhs(dataset_rtss, dataset_rtdose, rois, interrupt_flag, dose_limit=None):
    """
    :param dataset_rtss: RTSTRUCT DICOM dataset object.
    :param dataset_rtdose: RTDOSE DICOM dataset object.
    :param rois: Dictionary of ROI information.
    :param interrupt_flag: A threading.Event() object that tells the function to stop calculation.
    :param dose_limit: Limit of dose for DVH calculation.
    :return: Dictionary of all the DVHs of all the ROIs of the patient.
    """
    dict_dvh = {}
    roi_list = []
    for key in rois:
        roi_list.append(key)

    for roi in roi_list:
        dict_dvh[roi] = dvhcalc.get_dvh(dataset_rtss, dataset_rtdose, roi, dose_limit)
        if interrupt_flag.is_set():  # Stop calculating at the next DVH.
            return

    return dict_dvh
Ejemplo n.º 4
0
 def calc_dvh(self,
              key,
              limit=None,
              calculate_full_volume=True,
              use_structure_extents=False,
              interpolation_resolution=None,
              interpolation_segments=0):
     """Calculate a DVH for testing."""
     # Generate the calculated DVHs
     dvh = dvhcalc.get_dvh(
         self.rtss.ds,
         self.rtdose.ds,
         key,
         limit,
         calculate_full_volume=calculate_full_volume,
         use_structure_extents=use_structure_extents,
         interpolation_resolution=interpolation_resolution,
         interpolation_segments_between_planes=interpolation_segments)
     dvh.dose_units = 'Gy'
     return dvh
Ejemplo n.º 5
0
    def calculate_review_dvh(self):
        global x, y

        patches = {
            'x': [(0, [])],
            'y': [(0, [])],
            'roi_name': [(0, '')],
            'volume': [(0, 1)],
            'min_dose': [(0, '')],
            'mean_dose': [(0, '')],
            'max_dose': [(0, '')],
            'mrn': [(0, '')],
            'rx_dose': [(0, 1)]
        }

        try:
            if not self.sources.dvhs.data['x']:
                self.query.update_data()

            else:
                file_index = self.temp_dvh_info.mrn.index(
                    self.select_reviewed_mrn.value)
                roi_index = self.dvh_review_rois.index(
                    self.select_reviewed_dvh.value)
                structure_file = self.temp_dvh_info.structure[file_index]
                plan_file = self.temp_dvh_info.plan[file_index]
                dose_file = self.temp_dvh_info.dose[file_index]
                key = list(
                    self.temp_dvh_info.get_roi_names(
                        self.select_reviewed_mrn.value))[roi_index]

                rt_st = dicomparser.DicomParser(structure_file)
                rt_structures = rt_st.GetStructures()
                review_dvh = dvhcalc.get_dvh(structure_file, dose_file, key)
                dicompyler_plan = dicomparser.DicomParser(plan_file).GetPlan()

                roi_name = rt_structures[key]['name']
                volume = review_dvh.volume
                min_dose = review_dvh.min
                mean_dose = review_dvh.mean
                max_dose = review_dvh.max
                if not self.review_rx.value:
                    rx_dose = float(dicompyler_plan['rxdose']) / 100.
                    self.review_rx.value = str(round(rx_dose, 2))
                else:
                    rx_dose = round(float(self.review_rx.value), 2)

                x = review_dvh.bincenters
                if max(review_dvh.counts):
                    y = np.divide(review_dvh.counts, max(review_dvh.counts))
                else:
                    y = review_dvh.counts

                if self.radio_group_dose.active == 1:
                    f = 5000
                    bin_count = len(x)
                    new_bin_count = int(bin_count * f / (rx_dose * 100.))

                    x1 = np.linspace(0, bin_count, bin_count)
                    x2 = np.multiply(
                        np.linspace(0, new_bin_count, new_bin_count),
                        rx_dose * 100. / f)
                    y = np.interp(x2, x1, review_dvh.counts)
                    y = np.divide(y, np.max(y))
                    x = np.divide(np.linspace(0, new_bin_count, new_bin_count),
                                  f)

                if self.radio_group_volume.active == 0:
                    y = np.multiply(y, volume)

                patches = {
                    'x': [(0, x)],
                    'y': [(0, y)],
                    'roi_name': [(0, roi_name)],
                    'volume': [(0, volume)],
                    'min_dose': [(0, min_dose)],
                    'mean_dose': [(0, mean_dose)],
                    'max_dose': [(0, max_dose)],
                    'mrn': [(0, self.select_reviewed_mrn.value)],
                    'rx_dose': [(0, rx_dose)]
                }

        except:
            pass

        self.sources.dvhs.patch(patches)

        self.update_source_endpoint_calcs()
Ejemplo n.º 6
0
    def parse_patient_data(self):
        """Thread to load the patient data."""
        ptdata = self.patient
        patient = {}
        pbar = tqdm(total=100)
        if not 'images' in ptdata:
            # Look for DICOM data in the ptdata dictionary
            for rtdatatype in ptdata.keys():
                if isinstance(ptdata[rtdatatype], pydicom.dataset.FileDataset):
                    patient.update(
                        dicomparser.DicomParser(
                            ptdata[rtdatatype]).GetDemographics())
                    break
        if 'rtss' in ptdata:
            # pbar.update(20)
            pbar.n = 20
            pbar.set_description('Processing RT Structure Set...')
            pbar.refresh()

            d = dicomparser.DicomParser(ptdata['rtss'])
            s = d.GetStructures()
            for k in s.keys():
                s[k]['planes'] = d.GetStructureCoordinates(k)
                s[k]['thickness'] = d.CalculatePlaneThickness(s[k]['planes'])
            patient['structures'] = s
        if 'rtplan' in ptdata:
            pbar.n = 40
            pbar.refresh()
            pbar.set_description('Processing RT Plan...')
            patient['plan'] = dicomparser.DicomParser(
                ptdata['rtplan']).GetPlan()
        if 'rtdose' in ptdata:
            pbar.n = 60
            pbar.set_description('Processing RT Dose...')
            pbar.refresh()
            patient['dvhs'] = dicomparser.DicomParser(
                ptdata['rtdose']).GetDVHs()
            patient['dose'] = dicomparser.DicomParser(ptdata['rtdose'])
        if 'images' in ptdata:
            pbar.n = 80
            pbar.set_description('Processing Images...')
            pbar.refresh()
            if not 'id' in patient:
                patient.update(
                    dicomparser.DicomParser(
                        ptdata['images'][0]).GetDemographics())
            patient['images'] = []
            for image in ptdata['images']:
                patient['images'].append(dicomparser.DicomParser(image))
        if 'rxdose' in ptdata:
            if not 'plan' in patient:
                patient['plan'] = {}
            patient['plan']['rxdose'] = ptdata['rxdose']
        # if the min/max/mean dose was not present, calculate it and save it for each structure
        pbar.n = 90
        pbar.set_description('Processing DVH data...')
        pbar.refresh()
        if ('dvhs' in patient) and ('structures' in patient):
            # If the DVHs are not present, calculate them
            i = 0
            for key, structure in patient['structures'].items():
                # Only calculate DVHs if they are not present for the structure
                # or recalc all DVHs if the preference is set
                if ((not (key in patient['dvhs'].keys()))):
                    # Only calculate DVHs for structures, not applicators
                    # and only if the dose grid is present
                    if ((structure['name'].startswith('Applicator'))
                            or (not "PixelData" in patient['dose'].ds)):
                        continue
                    pbar.n = int(np.round(
                        10 * i / len(patient['structures']))) + 90
                    pbar.set_description('Calculating DVH for ' +
                                         structure['name'] + '...')
                    pbar.refresh()
                    # Limit DVH bins to 500 Gy due to high doses in brachy
                    dvh = dvhcalc.get_dvh(ptdata['rtss'], patient['dose'].ds,
                                          key, 50000)
                    if len(dvh.counts):
                        patient['dvhs'][key] = dvh
                    i += 1
            for key, dvh in patient['dvhs'].items():
                dvh.rx_dose = patient['plan']['rxdose'] / 100
        pbar.n = 100
        pbar.set_description('Done')
        pbar.close()
        self.parse_patient = patient
Ejemplo n.º 7
0
    def plot(self):

        #retrieve plan data & design DVH window
        plan1files = float(self.box5.get())
        plan2files = float(self.box6.get())
        self.newWindow = Toplevel(
            self.window)  #initiate new window for summed DVH
        self.newWindow.title("Recalculated DVH")
        #self.newWindow.iconbitmap("C:/Users/Owner/Documents/Rlogo2.ico")

        rtssfile1 = self.filename5  #structure file
        RTss1 = dicomparser.DicomParser(
            rtssfile1)  #read through structure file
        RTstructures1 = RTss1.GetStructures(
        )  #get each individual structure information

        #at least one dose file required for plan 1 and plan 2
        rtdosefile1 = self.filename1
        rtdosefile5 = self.filename6
        #conditional statements for multiple dose file input
        if plan1files >= 2:
            rtdosefile2 = self.filename2
        if plan1files >= 3:
            rtdosefile3 = self.filename3
        if plan1files >= 4:
            rtdosefile4 = self.filename4
        if plan2files >= 2:
            rtdosefile6 = self.filename7
        if plan2files >= 3:
            rtdosefile7 = self.filename8
        if plan2files >= 4:
            rtdosefile8 = self.filename9

        #structure to be analysed
        enteredtext = str(self.box4.get())

        #EQD2 parameters
        dpf1 = float(self.box1.get())  #plan 1 dose per fraction
        dpf2 = float(self.box2.get())  #plan 2 dose per fraction
        abratio = float(self.box3.get())  # tissue-specific alpha/beta ratio

        #EQD2 equation
        x1 = np.array((dpf1 + abratio) / (float(2.0) + abratio))
        x2 = np.array((dpf2 + abratio) / (float(2.0) + abratio))

        # Generation of the calculated DVHs
        #initiation of empty arrays to fill with correct structure data
        calcdvhs1 = {}
        calcdvhs2 = {}
        calcdvhs3 = {}
        calcdvhs4 = {}
        calcdvhs5 = {}
        calcdvhs6 = {}
        calcdvhs7 = {}
        calcdvhs8 = {}

        print("RED is calculating your EQD2 DVH....")
        print("Please wait, this could take a few moments")
        #iterate through dose file 1 to find correct stucture data
        for key, structure in RTstructures1.items():
            calcdvhs1[key] = dvhcalc.get_dvh(rtssfile1, rtdosefile1, key)
            if (key in calcdvhs1) and (structure['name'] == enteredtext) and (
                    len(calcdvhs1[key].counts)
                    and calcdvhs1[key].counts[0] != 0):
                print('1st Plan 1 DVH found for ' + structure['name'])
                data1 = np.array(calcdvhs1[key].bins) * x1
                lastdata1 = data1[-1]
                vola = calcdvhs1[key].counts * 100 / calcdvhs1[key].counts[0]

        # iterate through dose file 2 to find correct stucture data
        if plan1files >= 2:
            for key, structure in RTstructures1.items():
                calcdvhs2[key] = dvhcalc.get_dvh(rtssfile1, rtdosefile2, key)
                if (key in calcdvhs2) and (structure['name']
                                           == enteredtext) and (
                                               len(calcdvhs2[key].counts) and
                                               calcdvhs2[key].counts[0] != 0):
                    print('2nd Plan 1 DVH found for ' + structure['name'])
                    data2 = np.array(calcdvhs2[key].bins) * x1
                    lastdata2 = data2[-1]
                    volb = calcdvhs2[key].counts * 100 / calcdvhs2[key].counts[
                        0]

        # iterate through dose file 3 to find correct stucture data
        if plan1files >= 3:
            for key, structure in RTstructures1.items():
                calcdvhs3[key] = dvhcalc.get_dvh(rtssfile1, rtdosefile3, key)
                if (key in calcdvhs3) and (structure['name']
                                           == enteredtext) and (
                                               len(calcdvhs3[key].counts) and
                                               calcdvhs3[key].counts[0] != 0):
                    print('3rd Plan 1 DVH found for ' + structure['name'])
                    data3 = np.array(calcdvhs3[key].bins) * x1
                    lastdata3 = data3[-1]
                    volc = calcdvhs3[key].counts * 100 / calcdvhs3[key].counts[
                        0]

        # iterate through dose file 4 to find correct stucture data
        if plan1files >= 4:
            for key, structure in RTstructures1.items():
                calcdvhs4[key] = dvhcalc.get_dvh(rtssfile1, rtdosefile4, key)
                if (key in calcdvhs4) and (structure['name']
                                           == enteredtext) and (
                                               len(calcdvhs4[key].counts) and
                                               calcdvhs4[key].counts[0] != 0):
                    print('4th Plan 1 DVH found for ' + structure['name'])
                    data4 = np.array(calcdvhs4[key].bins) * x1
                    lastdata4 = data4[-1]
                    vold = calcdvhs4[key].counts * 100 / calcdvhs4[key].counts[
                        0]

        # iterate through dose file 5 to find correct stucture data
        for key, structure in RTstructures1.items():
            calcdvhs5[key] = dvhcalc.get_dvh(rtssfile1, rtdosefile5, key)
            if (key in calcdvhs5) and (structure['name'] == enteredtext) and (
                    len(calcdvhs5[key].counts)
                    and calcdvhs5[key].counts[0] != 0):
                print('1st Plan 2 DVH found for ' + structure['name'])
                data5 = np.array(calcdvhs5[key].bins) * x2
                lastdata5 = data5[-1]
                vole = calcdvhs5[key].counts * 100 / calcdvhs5[key].counts[0]

        # iterate through dose file 6 to find correct stucture data
        if plan2files >= 2:
            for key, structure in RTstructures1.items():
                calcdvhs6[key] = dvhcalc.get_dvh(rtssfile1, rtdosefile6, key)
                if (key in calcdvhs6) and (structure['name']
                                           == enteredtext) and (
                                               len(calcdvhs6[key].counts) and
                                               calcdvhs6[key].counts[0] != 0):
                    print('2nd Plan 2 DVH found for ' + structure['name'])
                    data6 = np.array(calcdvhs6[key].bins) * x2
                    lastdata6 = data6[-1]
                    volf = calcdvhs6[key].counts * 100 / calcdvhs6[key].counts[
                        0]

        # iterate through dose file 7 to find correct stucture data
        if plan2files >= 3:
            for key, structure in RTstructures1.items():
                calcdvhs7[key] = dvhcalc.get_dvh(rtssfile1, rtdosefile7, key)
                if (key in calcdvhs7) and (structure['name']
                                           == enteredtext) and (
                                               len(calcdvhs7[key].counts) and
                                               calcdvhs7[key].counts[0] != 0):
                    print('3rd Plan 2 DVH found for ' + structure['name'])
                    data7 = np.array(calcdvhs7[key].bins) * x2
                    lastdata7 = data7[-1]
                    volg = calcdvhs7[key].counts * 100 / calcdvhs7[key].counts[
                        0]

        # iterate through dose file 8 to find correct stucture data
        if plan2files >= 4:
            for key, structure in RTstructures1.items():
                calcdvhs8[key] = dvhcalc.get_dvh(rtssfile1, rtdosefile8, key)
                if (key in calcdvhs8) and (structure['name']
                                           == enteredtext) and (
                                               len(calcdvhs8[key].counts) and
                                               calcdvhs8[key].counts[0] != 0):
                    print('4th Plan 2 DVH found for ' + structure['name'])
                    data8 = np.array(calcdvhs8[key].bins) * x2
                    lastdata8 = data8[-1]
                    volh = calcdvhs8[key].counts * 100 / calcdvhs8[key].counts[
                        0]

        #initiation of DVH window
        fig = Figure()
        ax = fig.add_subplot(111)

        #addition of plan 1 dose data
        if plan1files == 1:
            totaldose1 = lastdata1
        if plan1files == 2:
            totaldose1 = lastdata1 + lastdata2
        if plan1files == 3:
            totaldose1 = lastdata1 + lastdata2 + lastdata3
        if plan1files == 4:
            totaldose1 = lastdata1 + lastdata2 + lastdata3 + lastdata4

        #addition of plan 2 dose data
        if plan2files == 1:
            totaldose2 = lastdata5
        if plan2files == 2:
            totaldose2 = lastdata5 + lastdata6
        if plan2files == 3:
            totaldose2 = lastdata5 + lastdata6 + lastdata7
        if plan2files == 4:
            totaldose2 = lastdata5 + lastdata6 + lastdata7 + lastdata8

        #conditional statements for plan 1 based on number of dose files
        #definition of volume and dose data
        if plan1files == 1:
            y = vola  #volume data
            y1len = len(y)
            x = np.linspace(0, totaldose1, num=y1len)  #dose data
        elif plan1files == 2:
            interyvaluesplan1b = np.concatenate((vola, volb),
                                                axis=0)  #summed volume data
            sorty21 = np.sort(interyvaluesplan1b
                              )  #sorted volume data array in ascending order
            vol21 = sorty21[::
                            -1]  #volume data array reversed to descending order
            y = vol21  #volume data
            y1len = len(y)
            x = np.linspace(0, totaldose1, num=y1len)  #dose data
        elif plan1files == 3:
            interyvalues1plan1a = np.concatenate((vola, volb), axis=0)
            interyvaluesplan1c = np.concatenate((interyvalues1plan1a, volc),
                                                axis=0)  #sumed volume data
            sorty31 = np.sort(interyvaluesplan1c
                              )  #sorted volume data array in ascending order
            vol31 = sorty31[::
                            -1]  #volume data array reversed to descending order
            y = vol31  #volume data
            y1len = len(y)
            x = np.linspace(0, totaldose1, num=y1len)  #dose data
        elif plan1files == 4:
            interyvalues1plan1b = np.concatenate((vola, volb), axis=0)
            interyvalues2plan1a = np.concatenate((volc, vold), axis=0)
            interyvaluesplan1d = np.concatenate(
                (interyvalues1plan1b, interyvalues2plan1a),
                axis=0)  #summed volume data
            sorty41 = np.sort(interyvaluesplan1d
                              )  #sorted volume data array in ascending order
            vol41 = sorty41[::
                            -1]  #volume data array reversed to descending order
            y = vol41
            y1len = len(y)
            x = np.linspace(0, totaldose1, num=y1len)  #dose data
        else:
            print("please check code starting at line 367")

        if plan2files == 1:
            b = vole  #volume data
            blen = len(b)
            a = np.linspace(0, totaldose2, num=blen)  #dose data

        elif plan2files == 2:
            interyvaluesplan2b = np.concatenate((vole, volf),
                                                axis=0)  #summed volume data
            sorty22 = np.sort(interyvaluesplan2b
                              )  # sorted volume data array in ascending order
            vol22 = sorty22[::
                            -1]  #volume data array reversed to descending order
            b = vol22
            blen = len(b)
            a = np.linspace(0, totaldose2, num=blen)  #dose data

        elif plan2files == 3:
            interyvalues1plan2a = np.concatenate((vole, volf), axis=0)
            interyvaluesplan2c = np.concatenate((interyvalues1plan2a, volg),
                                                axis=0)  #summed volume data
            sorty32 = np.sort(interyvaluesplan2c
                              )  #sorted volume data array in ascending order
            vol32 = sorty32[::
                            -1]  #volume data array reversed to descending order
            b = vol32
            blen = len(b)
            a = np.linspace(0, totaldose2, num=blen)  #dose data

        elif plan2files == 4:
            interyvalues1plan2b = np.concatenate((vole, volf), axis=0)
            interyvalues2plan2a = np.concatenate((volg, volh), axis=0)
            interyvaluesplan2d = np.concatenate(
                (interyvalues1plan2b, interyvalues2plan2a),
                axis=0)  #summed volume data
            sorty42 = np.sort(interyvaluesplan2d
                              )  #sorted volume data array in ascending order
            vol42 = sorty42[::
                            -1]  # volume data array reversed to descending order
            b = vol42
            blen = len(b)
            a = np.linspace(0, totaldose2, num=blen)  #dose data
        else:
            print("please check code starting at line 398")

        #plot plan 1 and plan 2 re-calculated DVH
        ax.plot(x, y, c='b')
        ax.plot(a, b, c='g')
        array = np.linspace(0, 100, 9000, endpoint=False)
        # get values from plan1 graph
        line1 = ax.lines[0]
        line1.get_xydata()
        xdat1 = line1.get_xdata()  #get x data
        fp1 = xdat1[::
                    -1]  # reverses x values to match reversed y values in array#
        ydat1 = line1.get_ydata()  #get y data
        xp1 = ydat1[::
                    -1]  # reverses y values from decreasng to increasing so interpolation function can work

        # get values from plan2 graph
        line2 = ax.lines[1]
        line2.get_xydata()
        xdat2 = line2.get_xdata()  #get xdata
        fp2 = xdat2[::
                    -1]  # reverses x values to match reversed y values in array
        ydat2 = line2.get_ydata()  #get y data
        xp2 = ydat2[::
                    -1]  # reverses y values from decreasng to increasing so interpolation function can work

        # set volume array to use for dose interpolation
        inter1 = np.interp([array], xp1, fp1)  # interpolation of plan1 dose
        reshapeinter1 = np.reshape(inter1, (9000, 1))
        inter2 = np.interp([array], xp2, fp2)  # interpolation of plan2 dose
        reshapeinter2 = np.reshape(inter2, (9000, 1))
        xvalues = reshapeinter1 + reshapeinter2  # adding plan1 and plan2 dose
        reshapearray = np.reshape(
            array, (9000, 1))  # array of specified %volume intervals

        #define strings
        dpf12 = str(dpf1)
        dpf21 = str(dpf2)
        abdisplay = str(abratio)

        #plot summed re-calculated DVH in seperate window
        plt.plot(xvalues, reshapearray, c='r')
        plt.title("Recalculated Summed DVH")
        # plt.iconbitmap("C:/Users/Owner/Documents/Rlogo2.ico")
        plt.title("Summed EQD2 DVH for " + enteredtext + " a/b=" + abdisplay +
                  " dpf Plan 1=" + dpf12 + " dpf Plan 2=" + dpf21)
        ax.legend(["Plan 1", "Plan 2"])
        ax.set_title("EQD2 DVH for " + enteredtext + " a/b=" + abdisplay +
                     " dpf Plan 1=" + dpf12 + " dpf Plan 2=" + dpf21)
        ax.set_ylabel("Volume %", fontsize=14)
        ax.set_xlabel("EQD2 Gy", fontsize=14)
        plt.legend(["Plan 1 + 2"])
        plt.ylabel("Volume %", fontsize=14)
        plt.xlabel("EQD2 Gy", fontsize=14)
        ax.set_axisbelow(True)

        #design of summed dvh
        plt.grid(color='gray', linestyle='dashed')
        datacursor()
        ax.yaxis.grid(color='gray', linestyle='dashed')
        ax.xaxis.grid(color='gray', linestyle='dashed')

        #draw sumed DVH
        canvas = FigureCanvasTkAgg(fig, master=self.newWindow)
        canvas.get_tk_widget().grid(row=10)
        canvas.draw()
        plt.show()

        #initiate toolbar for analysis
        toolbarFrame = Frame(master=self.newWindow)
        toolbarFrame.grid(row=20)
        toolbar = NavigationToolbar2Tk(canvas, toolbarFrame)
        toolbar.draw()
Ejemplo n.º 8
0
 def calculate_dvh(self, key):
     if key not in list(self.dvh):
         files = self.plans[self.select_plan.value]
         self.dvh[key] = dvhcalc.get_dvh(files['rtstruct'], files['rtdose'],
                                         key)
Ejemplo n.º 9
0
    x, y, z, dx, dy, dz, volume = oncdose.process_file(dosename)
    print('dx=', dx, 'dy=', dy, 'dz=', dz, 'dose volume', np.shape(volume))

if args.structure:
    structname = args.structure
    structures = pydicom.dcmread(structname)

plt.figure()

#we need to get an accurate dose resolution to perform the calculations

for k in range(0, structures[0x3006, 0x0039].VM):
    print(dx, dy)
    calcdvh = dvhcalc.get_dvh(
        structname,
        dosename,
        k,
        interpolation_resolution=(dy, dx),
        interpolation_segments_between_planes=10).relative_volume
    # calcdvh = dvhcalc.get_dvh(structname, dosename, k).relative_volume
    # calcdvh.volume_units = '%'
    # print(calcdvh.relative_volume)
    calcdvh.plot()

plt.show()

# calcdvh=dvhcalc.get_dvh(structname,dosename,0)
# print(calcdvh.describe())
# print(calcdvh.cumulative)
# plt.figure()
# calcdvh.plot()
# plt.show()
Ejemplo n.º 10
0
def calc_dvh_worker(rtss, dose, roi, queue, dose_limit=None):
    dvh = {}
    dvh[roi] = dvhcalc.get_dvh(rtss, dose, roi, dose_limit)
    queue.put(dvh)
Ejemplo n.º 11
0
    def test_FF_decubitus_left(self):
        """Test DVH for feet-first decubitus left orientation."""
        self.dose.ImageOrientationPatient = [0, 1, 0, 1, 0, 0]
        self.dose.PixelSpacing = [2.0, 1.0]  # between Rows, Columns
        # original ipp = [2, 12, -20]
        # Then X = r * dr + ipp[0], X increases down the rows
        #  and Y = c * dc + ipp[1], Y increases across cols
        # (https://nipy.org/nibabel/dicom/dicom_orientation.html
        # #dicom-affine-formula)

        # In this test, we also shift Z so three structure planes use the
        #    first three dose planes rather than the middle three,
        #    just to ensure asymmetry in z direction is checked.
        #    Note, planes should really be reversed in pixel array, but doesn't
        #    matter since contour is identical on each slice.
        self.dose.ImagePositionPatient = [2, 12, 10]  # X Y Z top left
        # Below show contours box of (3, 14.5) - (7, 17.5) on dose grid
        #      Y=12  13  14  15  16  17      19
        # X=2   [ 0,  0,  0,  3,  4,  5,  6,  7],
        #                   |-----------|
        #   4   [ 0,  0,  0,  3,  4,  5,  6,  7]
        #   6   [ 0,  0,  0,  3,  4,  5,  6,  7]
        #                   |-----------|
        #   8   [ 3,  3,  3,  6,  7,  8,  9, 10]
        #  10   [ 4,  4,  4,  7,  8,  9, 10, 11]
        #  12   [ 5,  5,  5,  8,  9, 10, 11, 12]
        #  14   [ 6,  6,  6,  9, 10, 11, 12, 13]]

        #      Y=12  13  14                  19
        # X=2   [10, 10, 10, 13, 14, 15, 16, 17],
        #                   |-----------|
        #   4   [10, 10, 10, 13, 14, 15, 16, 17]
        #   6   [10, 10, 10, 13, 14, 15, 16, 17]
        #                   |-----------|
        #   8   [13, 13, 13, 16, 17, 18, 19, 20]
        #  10   [14, 14, 14, 17, 18, 19, 20, 21]
        #  12   [15, 15, 15, 18, 19, 20, 21, 22]
        #  14   [16, 16, 16, 19, 20, 21, 22, 23]]

        #      Y=12  13  14                  19
        # X=2   [20, 20, 20, 23, 24, 25, 26, 27]
        #                   |-----------|
        #   4   [20, 20, 20, 23, 24, 25, 26, 27]
        #   6   [20, 20, 20, 23, 24, 25, 26, 27]
        #                   |-----------|
        #   8   [23, 23, 23, 26, 27, 28, 29, 30]
        #  10   [24, 24, 24, 27, 28, 29, 30, 31]
        #  12   [25, 25, 25, 28, 29, 30, 31, 32]
        #  14   [...]

        #                          3
        expected_counts = [0] * 3 + [
            2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2
        ]
        #                         13                            23
        dvh = get_dvh(self.ss, self.dose, 1)
        diffl = dvh.differential
        # Counts are normalized to total, and to volume,
        # So undo that here for test dose grid.
        # 18=num dose voxels inside struct; 0.36=volume
        got_counts = diffl.counts * 18 / 0.36
        assert_allclose(got_counts, expected_counts)
Ejemplo n.º 12
0
 def test_not_implemented_orientations(self):
     """Test unhandled orientations raise NotImplementedError."""
     self.dose.ImageOrientationPatient = [0.7071, 0.7071, 0, 1, 0, 0]
     with self.assertRaises(NotImplementedError):
         _ = get_dvh(self.ss, self.dose, 1)
Ejemplo n.º 13
0
    def LoadPatientDataThread(self, parent, ptdata, progressFunc, updateFunc):
        """Thread to load the patient data."""

        # Call the progress function to update the gui
        wx.CallAfter(progressFunc, 0, 0, 'Processing patient data...')
        patient = {}

        if not 'images' in ptdata:
            #Look for DICOM data in the ptdata dictionary
            for rtdatatype in ptdata.keys():
                if isinstance(ptdata[rtdatatype], pydicom.dataset.FileDataset):
                    patient.update(dp(ptdata[rtdatatype]).GetDemographics())
                    break
        if 'rtss' in ptdata:
            wx.CallAfter(progressFunc, 20, 100,
                         'Processing RT Structure Set...')
            d = dp(ptdata['rtss'])
            s = d.GetStructures()
            for k in s.keys():
                s[k]['planes'] = d.GetStructureCoordinates(k)
                s[k]['thickness'] = d.CalculatePlaneThickness(s[k]['planes'])
            patient['structures'] = s
        if 'rtplan' in ptdata:
            wx.CallAfter(progressFunc, 40, 100, 'Processing RT Plan...')
            patient['plan'] = dp(ptdata['rtplan']).GetPlan()
        if 'rtdose' in ptdata:
            wx.CallAfter(progressFunc, 60, 100, 'Processing RT Dose...')
            patient['dvhs'] = dp(ptdata['rtdose']).GetDVHs()
            patient['dose'] = dp(ptdata['rtdose'])
        if 'images' in ptdata:
            wx.CallAfter(progressFunc, 80, 100, 'Processing Images...')
            if not 'id' in patient:
                patient.update(dp(ptdata['images'][0]).GetDemographics())
            patient['images'] = []
            for image in ptdata['images']:
                patient['images'].append(dp(image))
        if 'rxdose' in ptdata:
            if not 'plan' in patient:
                patient['plan'] = {}
            patient['plan']['rxdose'] = ptdata['rxdose']
        # if the min/max/mean dose was not present, calculate it and save it for each structure
        wx.CallAfter(progressFunc, 90, 100, 'Processing DVH data...')
        if ('dvhs' in patient) and ('structures' in patient):
            # If the DVHs are not present, calculate them
            i = 0
            for key, structure in patient['structures'].items():
                # Only calculate DVHs if they are not present for the structure
                # or recalc all DVHs if the preference is set
                if ((not (key in patient['dvhs'].keys()))
                        or (self.dvhRecalc == 'Always Recalculate DVH')):
                    # Only calculate DVHs for structures, not applicators
                    # and only if the dose grid is present
                    if ((structure['name'].startswith('Applicator'))
                            or (not "PixelData" in patient['dose'].ds)):
                        continue
                    wx.CallAfter(
                        progressFunc, 10 * i / len(patient['structures']) + 90,
                        100,
                        'Calculating DVH for ' + structure['name'] + '...')
                    # Limit DVH bins to 500 Gy due to high doses in brachy
                    dvh = dvhcalc.get_dvh(ptdata['rtss'], patient['dose'].ds,
                                          key, 50000)
                    if len(dvh.counts):
                        patient['dvhs'][key] = dvh
                    i += 1
            for key, dvh in patient['dvhs'].items():
                dvh.rx_dose = patient['plan']['rxdose'] / 100
        wx.CallAfter(progressFunc, 100, 100, 'Done')
        wx.CallAfter(updateFunc, patient)
Ejemplo n.º 14
0
 def calc_dvh(self, key, limit=None, calculate_full_volume=True):
     """Calculate a DVH for testing."""
     # Generate the calculated DVHs
     return dvhcalc.get_dvh(
         self.rtss.ds, self.rtdose.ds, key, limit,
         calculate_full_volume=calculate_full_volume)
Ejemplo n.º 15
0
    def LoadPatientDataThread(self, parent, ptdata, progressFunc, updateFunc):
        """Thread to load the patient data."""

        # Call the progress function to update the gui
        wx.CallAfter(progressFunc, 0, 0, 'Processing patient data...')
        patient = {}

        if not 'images' in ptdata:
            #Look for DICOM data in the ptdata dictionary
            for rtdatatype in ptdata.keys():
                if isinstance(ptdata[rtdatatype], pydicom.dataset.FileDataset):
                    patient.update(dp(ptdata[rtdatatype]).GetDemographics())
                    break
        if 'rtss' in ptdata:
            wx.CallAfter(progressFunc, 20, 100, 'Processing RT Structure Set...')
            d = dp(ptdata['rtss'])
            s = d.GetStructures()
            for k in s.keys():
                s[k]['planes'] = d.GetStructureCoordinates(k)
                s[k]['thickness'] = d.CalculatePlaneThickness(s[k]['planes'])
            patient['structures'] = s
        if 'rtplan' in ptdata:
            wx.CallAfter(progressFunc, 40, 100, 'Processing RT Plan...')
            patient['plan'] = dp(ptdata['rtplan']).GetPlan()
        if 'rtdose' in ptdata:
            wx.CallAfter(progressFunc, 60, 100, 'Processing RT Dose...')
            patient['dvhs'] = dp(ptdata['rtdose']).GetDVHs()
            patient['dose'] = dp(ptdata['rtdose'])
        if 'images' in ptdata:
            wx.CallAfter(progressFunc, 80, 100, 'Processing Images...')
            if not 'id' in patient:
                patient.update(dp(ptdata['images'][0]).GetDemographics())
            patient['images'] = []
            for image in ptdata['images']:
                patient['images'].append(dp(image))
        if 'rxdose' in ptdata:
            if not 'plan' in patient:
                patient['plan'] = {}
            patient['plan']['rxdose'] = ptdata['rxdose']
        # if the min/max/mean dose was not present, calculate it and save it for each structure
        wx.CallAfter(progressFunc, 90, 100, 'Processing DVH data...')
        if ('dvhs' in patient) and ('structures' in patient):
            # If the DVHs are not present, calculate them
            i = 0
            for key, structure in patient['structures'].items():
                # Only calculate DVHs if they are not present for the structure
                # or recalc all DVHs if the preference is set
                if ((not (key in patient['dvhs'].keys())) or
                    (self.dvhRecalc == 'Always Recalculate DVH')):
                    # Only calculate DVHs for structures, not applicators
                    # and only if the dose grid is present
                    if ((structure['name'].startswith('Applicator')) or
                        (not "PixelData" in patient['dose'].ds)):
                        continue
                    wx.CallAfter(progressFunc,
                                 10*i/len(patient['structures'])+90, 100,
                                 'Calculating DVH for ' + structure['name'] +
                                 '...')
                    # Limit DVH bins to 500 Gy due to high doses in brachy
                    dvh = dvhcalc.get_dvh(ptdata['rtss'], patient['dose'].ds, key, 50000)
                    if len(dvh.counts):
                        patient['dvhs'][key] = dvh
                    i += 1
            for key, dvh in patient['dvhs'].items():
                dvh.rx_dose = patient['plan']['rxdose'] / 100
        wx.CallAfter(progressFunc, 100, 100, 'Done')
        wx.CallAfter(updateFunc, patient)
Ejemplo n.º 16
0
 def calc_dvh(self, key, limit=None):
     """Calculate a DVH for testing."""
     # Generate the calculated DVHs
     return dvhcalc.get_dvh(self.rtss.ds, self.rtdose.ds, key, limit)
Ejemplo n.º 17
0
def calc_dvh_worker(rtss, dose, roi, queue, thickness, dose_limit=None):
    dvh = {}
    dvh[roi] = \
        dvhcalc.get_dvh(rtss, dose, roi, dose_limit, thickness=thickness)
    queue.put(dvh)
Ejemplo n.º 18
0
    def __init__(self, structure_file, dose_file):
        # Get ROI Category Map
        database_rois = DatabaseROIs()

        # Import RT Structure and RT Dose files using dicompyler
        rt_structure_dicom = dicom.read_file(structure_file)
        mrn = rt_structure_dicom.PatientID
        study_instance_uid = rt_structure_dicom.StudyInstanceUID

        rt_structure = dicomparser.DicomParser(structure_file)
        rt_structures = rt_structure.GetStructures()

        if hasattr(rt_structure_dicom, 'PhysiciansOfRecord'):
            physician = rt_structure_dicom.PhysiciansOfRecord.upper()
        elif hasattr(rt_structure_dicom, 'ReferringPhysicianName'):
            physician = rt_structure_dicom.ReferringPhysicianName.upper()
        else:
            physician = '(NULL)'

        values = {}
        row_counter = 0
        self.dvhs = {}
        for key in rt_structures:
            # Import DVH from RT Structure and RT Dose files
            if rt_structures[key]['type'] != 'MARKER':

                current_dvh_calc = dvhcalc.get_dvh(structure_file, dose_file, key)
                self.dvhs[row_counter] = current_dvh_calc.counts
                if current_dvh_calc.volume > 0:
                    print('Importing', current_dvh_calc.name, sep=' ')
                    if rt_structures[key]['name'].lower().find('itv') == 0:
                        roi_type = 'ITV'
                    else:
                        roi_type = rt_structures[key]['type']
                    current_roi_name = clean_name(rt_structures[key]['name'])

                    if database_rois.is_roi(current_roi_name):
                        if database_rois.is_physician(physician):
                            physician_roi = database_rois.get_physician_roi(physician, current_roi_name)
                            institutional_roi = database_rois.get_institutional_roi(physician, physician_roi)
                        else:
                            if current_roi_name in database_rois.institutional_rois:
                                institutional_roi = current_roi_name
                            else:
                                institutional_roi = 'uncategorized'
                            physician_roi = 'uncategorized'
                    else:
                        institutional_roi = 'uncategorized'
                        physician_roi = 'uncategorized'

                    coord = rt_structure.GetStructureCoordinates(key)
                    roi_coord_str = dicompyler_roi_coord_to_db_string(rt_structure.GetStructureCoordinates(key))
                    try:
                        surface_area = surface_area_of_roi(coord)
                    except:
                        print("Surface area calculation failed for key, name: %s, %s" % (key, current_dvh_calc.name))
                        surface_area = '(NULL)'
                    # volume = calc_volume(get_planes_from_string(roi_coord_str))

                    current_dvh_row = DVHRow(mrn,
                                             study_instance_uid,
                                             institutional_roi,
                                             physician_roi,
                                             current_roi_name,
                                             roi_type,
                                             current_dvh_calc.volume,
                                             current_dvh_calc.min,
                                             current_dvh_calc.mean,
                                             current_dvh_calc.max,
                                             ','.join(['%.2f' % num for num in current_dvh_calc.counts]),
                                             roi_coord_str,
                                             surface_area)
                    values[row_counter] = current_dvh_row
                    row_counter += 1

        self.count = row_counter
        dvh_range = range(self.count)

        for attr in dir(values[0]):
            if not attr.startswith('_'):
                setattr(self, attr, [getattr(values[x], attr) for x in dvh_range])
Ejemplo n.º 19
0
    def LoadPatientDataThread(self, parent, ptdata, progressFunc, updateFunc):
        """Thread to load the patient data."""

        # Call the progress function to update the gui
        wx.CallAfter(progressFunc, 0, 0, 'Processing patient data...')
        patient = {}

        if not 'images' in ptdata:
            #Look for DICOM data in the ptdata dictionary
            for rtdatatype in ptdata.keys():
                if isinstance(ptdata[rtdatatype], pydicom.dataset.FileDataset):
                    patient.update(dp(ptdata[rtdatatype]).GetDemographics())
                    break
        if 'rtss' in ptdata:
            wx.CallAfter(progressFunc, 20, 100,
                         'Processing RT Structure Set...')
            d = dp(ptdata['rtss'])
            s = d.GetStructures()
            for k in s.keys():
                s[k]['planes'] = d.GetStructureCoordinates(k)
                s[k]['thickness'] = d.CalculatePlaneThickness(s[k]['planes'])
            patient['structures'] = s
        if 'rtplan' in ptdata:
            wx.CallAfter(progressFunc, 40, 100, 'Processing RT Plan...')
            patient['plan'] = dp(ptdata['rtplan']).GetPlan()
        if 'rtdose' in ptdata:
            wx.CallAfter(progressFunc, 60, 100, 'Processing RT Dose...')
            patient['dvhs'] = dp(ptdata['rtdose']).GetDVHs()
            patient['dose'] = dp(ptdata['rtdose'])
        if 'images' in ptdata:
            wx.CallAfter(progressFunc, 80, 100, 'Processing Images...')
            if not 'id' in patient:
                patient.update(dp(ptdata['images'][0]).GetDemographics())
            patient['images'] = []
            for image in ptdata['images']:
                patient['images'].append(dp(image))
        if 'rxdose' in ptdata:
            if not 'plan' in patient:
                patient['plan'] = {}
            patient['plan']['rxdose'] = ptdata['rxdose']
        # if the min/max/mean dose was not present, calculate it and save it for each structure
        wx.CallAfter(progressFunc, 90, 100, 'Processing DVH data...')
        if ('dvhs' in patient) and ('structures' in patient):
            # If the DVHs are not present, calculate them
            i = 0
            # Grabbing patient ID
            dvh_patientID = ptdata['rtdose'].PatientID
            csv_filename = str(dvh_patientID) + '.csv'

            dvh_csv_list = []
            # maximum dose of all ROIs
            max_roi_dose = 0
            # csv Header
            csv_header = []

            for key, structure in patient['structures'].items():
                # Initialize a list for dvh exporting to csv
                dvh_roi_list = []

                # Only calculate DVHs if they are not present for the structure
                # or recalc all DVHs if the preference is set
                if ((not (key in patient['dvhs'].keys()))
                        or (self.dvhRecalc == 'Always Recalculate DVH')):
                    # Only calculate DVHs for structures, not applicators
                    # and only if the dose grid is present
                    if ((structure['name'].startswith('Applicator'))
                            or (not "PixelData" in patient['dose'].ds)):
                        continue
                    wx.CallAfter(
                        progressFunc, 10 * i / len(patient['structures']) + 90,
                        100,
                        'Calculating DVH for ' + structure['name'] + '...')
                    # Limit DVH bins to 500 Gy due to high doses in brachy
                    dvh = dvhcalc.get_dvh(ptdata['rtss'], patient['dose'].ds,
                                          key, 50000)

                    # Retrieve roi name
                    dvh_roiName = dvh.name
                    # Retrieve roi dvh volume
                    dvh_roiVolume = dvh.volume
                    # Append info
                    dvh_roi_list.append(dvh_patientID)
                    dvh_roi_list.append(dvh_roiName)
                    dvh_roi_list.append(dvh_roiVolume)
                    #
                    dvh_roiDose = dvh.relative_volume.counts

                    for i in range(0, len(dvh_roiDose), 10):
                        dvh_roi_list.append(dvh_roiDose[i])
                        if i > max_roi_dose:
                            max_roi_dose = i

                    dvh_csv_list.append(dvh_roi_list)

                    if len(dvh.counts):
                        patient['dvhs'][key] = dvh
                    i += 1

            csv_header.append('Hash ID')
            csv_header.append('ROI')
            csv_header.append('Volume (mL)')

            for i in range(0, max_roi_dose + 1, 10):
                csv_header.append(str(i) + 'cGy')

            pddf_csv = pd.DataFrame(dvh_csv_list, columns=csv_header).round(2)
            pddf_csv.fillna(0.0, inplace=True)

            pddf_csv.set_index('Hash ID', inplace=True)

            if not os.path.exists(self.path + '/CSV'):
                os.makedirs(self.path + '/CSV')

            pddf_csv.to_csv(self.path + '/CSV/' + 'DVH_' + csv_filename)

            for key, dvh in patient['dvhs'].items():
                dvh.rx_dose = patient['plan']['rxdose'] / 100

        wx.CallAfter(progressFunc, 100, 100, 'Done')
        wx.CallAfter(updateFunc, patient)
def calc_dvh(rtss,rtdose,structure_id,px):
    """Calculate a dvh object from input files and structure id, and assign the prescription to the dvh object.
    All 3 files must be provided."""
    dvh = dvhcalc.get_dvh(rtss,rtdose,structure_id)
    dvh.rx_dose = px
    return dvh
Ejemplo n.º 21
0
    dp = dicomparser.DicomParser(Fichier_RS)

    # i.e. Get a dict of structure information
    structures = dp.GetStructures()
    New_structures = []

    for j in List_ROI:
        #print(j)
        try:
            for i in list(structures):

                if j == structures[i]["name"]:

                    indice = i

                    calcdvh = dvhcalc.get_dvh(str(Fichier_RS), str(Fichier_RD),
                                              indice)
                    print('\n pour le  ' + str(structures[i]["name"]) + ' : ',
                          '\n \t Dose max : ', calcdvh.max,
                          " \n \t Dose min : ", calcdvh.min, '\n \t D1cc : ',
                          calcdvh.D1cc, '\n \t D50 ', calcdvh.D50)

        except:
            pass

# print(indice_Sein_G,indice_Coeur)

#print(List)

# # Calculate a DVH from DICOM RT data
# calcdvh = dvhcalc.get_dvh(str(Fichier_RS), str(Fichier_RD), indice_Coeur)
# print('pour le coeur' ,calcdvh.max,calcdvh.min,calcdvh.D50)