def update_treatment_volume_overlap_in_db(study_instance_uid, roi_name):
    """
    This function will recalculate the PTV overlap of an roi based on data in the SQL DB.
    :param study_instance_uid: uid as specified in SQL DB
    :param roi_name: roi_name as specified in SQL DB
    """

    oar_coordinates_string = DVH_SQL().query(
        'dvhs', 'roi_coord_string',
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))

    ptv_coordinates_strings = DVH_SQL().query(
        'dvhs', 'roi_coord_string',
        "study_instance_uid = '%s' and roi_type like 'PTV%%'" %
        study_instance_uid)

    if ptv_coordinates_strings:
        oar = roi_tools.get_planes_from_string(oar_coordinates_string[0][0])

        ptvs = [
            roi_tools.get_planes_from_string(ptv[0])
            for ptv in ptv_coordinates_strings
        ]

        tv = roi_tools.get_union(ptvs)
        overlap = roi_tools.calc_roi_overlap(oar, tv)

        DVH_SQL().update(
            'dvhs', 'ptv_overlap', round(float(overlap), 2),
            "study_instance_uid = '%s' and roi_name = '%s'" %
            (study_instance_uid, roi_name))
def update_dist_to_ptv_centroids_in_db(study_instance_uid, roi_name):
    """
    This function will recalculate the OARtoPTV centroid distance based on data in the SQL DB.
    :param study_instance_uid: uid as specified in SQL DB
    :param roi_name: roi_name as specified in SQL DB
    """

    oar_centroid_string = DVH_SQL().query(
        'dvhs', 'centroid', "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))
    oar_centroid = np.array(
        [float(i) for i in oar_centroid_string[0][0].split(',')])

    ptv_coordinates_strings = DVH_SQL().query(
        'dvhs', 'roi_coord_string',
        "study_instance_uid = '%s' and roi_type like 'PTV%%'" %
        study_instance_uid)

    if ptv_coordinates_strings:

        ptvs = [
            roi_tools.get_planes_from_string(ptv[0])
            for ptv in ptv_coordinates_strings
        ]
        tv = roi_tools.get_union(ptvs)
        ptv_centroid = np.array(roi_tools.calc_centroid(tv))

        dist_to_ptv_centroids = float(
            np.linalg.norm(ptv_centroid - oar_centroid)) / 10.

        DVH_SQL().update(
            'dvhs', 'dist_to_ptv_centroids', round(dist_to_ptv_centroids, 3),
            "study_instance_uid = '%s' and roi_name = '%s'" %
            (study_instance_uid, roi_name))
def update_spread_in_db(study_instance_uid, roi_name):
    """
    This function will recalculate the spread of an roi based on data in the SQL DB.
    :param study_instance_uid: uid as specified in SQL DB
    :param roi_name: roi_name as specified in SQL DB
    """

    coordinates_string = DVH_SQL().query(
        'dvhs', 'roi_coord_string',
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))

    roi = roi_tools.get_planes_from_string(coordinates_string[0][0])
    spread = calc_spread(roi)

    spread = [str(round(v / 10., 3)) for v in spread]

    DVH_SQL().update(
        'dvhs', 'spread_x', spread[0],
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))
    DVH_SQL().update(
        'dvhs', 'spread_y', spread[1],
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))
    DVH_SQL().update(
        'dvhs', 'spread_z', spread[2],
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))
    def update_roi_viewer_data(self):

        # if roi_name is an empty string (default selection), return an empty data set
        if not self.roi_select.value:
            return {'0': {'x': [], 'y': [], 'z': []}}

        roi_data = {}
        roi_coord_string = DVH_SQL().query(
            'dvhs', 'roi_coord_string',
            "study_instance_uid = '%s' and roi_name = '%s'" %
            (self.uid_select.value, self.roi_select.value))
        roi_planes = get_planes_from_string(roi_coord_string[0][0])
        for z_plane in list(roi_planes):
            x, y, z = [], [], []
            for polygon in roi_planes[z_plane]:
                initial_polygon_index = len(x)
                for point in polygon:
                    x.append(point[0])
                    y.append(point[1])
                    z.append(point[2])
                x.append(x[initial_polygon_index])
                y.append(y[initial_polygon_index])
                z.append(z[initial_polygon_index])
                x.append(float('nan'))
                y.append(float('nan'))
                z.append(float('nan'))
            roi_data[z_plane] = {'x': x, 'y': y, 'z': z}

        self.roi_viewer_data[self.roi_number] = roi_data
    def update_tv_data(self):
        self.tv_data = {}

        uid = self.uid_select.value
        ptv_coordinates_strings = DVH_SQL().query(
            'dvhs', 'roi_coord_string',
            "study_instance_uid = '%s' and roi_type like 'PTV%%'" % uid)

        if ptv_coordinates_strings:

            ptvs = [
                get_planes_from_string(ptv[0])
                for ptv in ptv_coordinates_strings
            ]
            tv_planes = get_union(ptvs)

        for z_plane in list(tv_planes):
            x, y, z = [], [], []
            for polygon in tv_planes[z_plane]:
                initial_polygon_index = len(x)
                for point in polygon:
                    x.append(point[0])
                    y.append(point[1])
                    z.append(point[2])
                x.append(x[initial_polygon_index])
                y.append(y[initial_polygon_index])
                z.append(z[initial_polygon_index])
                x.append(float('nan'))
                y.append(float('nan'))
                z.append(float('nan'))
                self.tv_data[z_plane] = {'x': x, 'y': y, 'z': z}
def update_volumes_in_db(study_instance_uid, roi_name):
    """
    This function will recalculate the volume of an roi based on data in the SQL DB.
    :param study_instance_uid: uid as specified in SQL DB
    :param roi_name: roi_name as specified in SQL DB
    """

    coordinates_string = DVH_SQL().query(
        'dvhs', 'roi_coord_string',
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))

    roi = roi_tools.get_planes_from_string(coordinates_string[0][0])

    volume = roi_tools.calc_volume(roi)

    DVH_SQL().update(
        'dvhs', 'volume', round(float(volume), 2),
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))
def update_surface_area_in_db(study_instance_uid, roi_name):
    """
    This function will recalculate the surface area of an roi based on data in the SQL DB.
    :param study_instance_uid: uid as specified in SQL DB
    :param roi_name: roi_name as specified in SQL DB
    """

    coordinates_string = DVH_SQL().query(
        'dvhs', 'roi_coord_string',
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))

    roi = roi_tools.get_planes_from_string(coordinates_string[0][0])

    surface_area = roi_tools.surface_area_of_roi(roi,
                                                 coord_type="sets_of_points")

    DVH_SQL().update(
        'dvhs', 'surface_area', round(float(surface_area), 2),
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))
def update_centroid_in_db(study_instance_uid, roi_name):
    """
    This function will recalculate the centroid of an roi based on data in the SQL DB.
    :param study_instance_uid: uid as specified in SQL DB
    :param roi_name: roi_name as specified in SQL DB
    """

    coordinates_string = DVH_SQL().query(
        'dvhs', 'roi_coord_string',
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))

    roi = roi_tools.get_planes_from_string(coordinates_string[0][0])
    centroid = roi_tools.calc_centroid(roi)

    centroid = [str(round(v, 3)) for v in centroid]

    DVH_SQL().update(
        'dvhs', 'centroid', ','.join(centroid),
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))
def update_cross_section_in_db(study_instance_uid, roi_name):
    """
    This function will recalculate the centoid of an roi based on data in the SQL DB.
    :param study_instance_uid: uid as specified in SQL DB
    :param roi_name: roi_name as specified in SQL DB
    """

    coordinates_string = DVH_SQL().query(
        'dvhs', 'roi_coord_string',
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))

    roi = roi_tools.get_planes_from_string(coordinates_string[0][0])
    area = roi_tools.calc_cross_section(roi)

    DVH_SQL().update(
        'dvhs', 'cross_section_max', area['max'],
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))

    DVH_SQL().update(
        'dvhs', 'cross_section_median', area['median'],
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))
def update_min_distances_in_db(study_instance_uid, roi_name):
    """
    This function will recalculate the min, mean, median, and max PTV distances an roi based on data in the SQL DB.
    :param study_instance_uid: uid as specified in SQL DB
    :param roi_name: roi_name as specified in SQL DB
    """

    oar_coordinates_string = DVH_SQL().query(
        'dvhs', 'roi_coord_string',
        "study_instance_uid = '%s' and roi_name = '%s'" %
        (study_instance_uid, roi_name))

    ptv_coordinates_strings = DVH_SQL().query(
        'dvhs', 'roi_coord_string',
        "study_instance_uid = '%s' and roi_type like 'PTV%%'" %
        study_instance_uid)

    if ptv_coordinates_strings:

        oar_coordinates = roi_tools.get_roi_coordinates_from_string(
            oar_coordinates_string[0][0])

        ptvs = [
            roi_tools.get_planes_from_string(ptv[0])
            for ptv in ptv_coordinates_strings
        ]
        tv_coordinates = roi_tools.get_roi_coordinates_from_planes(
            roi_tools.get_union(ptvs))

        try:
            min_distances = roi_tools.get_min_distances_to_target(
                oar_coordinates, tv_coordinates)
            dth = calc_dth(min_distances)
            dth_string = ','.join(['%.3f' % num for num in dth])

            DVH_SQL().update(
                'dvhs', 'dist_to_ptv_min',
                round(float(np.min(min_distances)),
                      2), "study_instance_uid = '%s' and roi_name = '%s'" %
                (study_instance_uid, roi_name))

            DVH_SQL().update(
                'dvhs', 'dist_to_ptv_mean',
                round(float(np.mean(min_distances)),
                      2), "study_instance_uid = '%s' and roi_name = '%s'" %
                (study_instance_uid, roi_name))

            DVH_SQL().update(
                'dvhs', 'dist_to_ptv_median',
                round(float(np.median(min_distances)),
                      2), "study_instance_uid = '%s' and roi_name = '%s'" %
                (study_instance_uid, roi_name))

            DVH_SQL().update(
                'dvhs', 'dist_to_ptv_max',
                round(float(np.max(min_distances)),
                      2), "study_instance_uid = '%s' and roi_name = '%s'" %
                (study_instance_uid, roi_name))

            DVH_SQL().update(
                'dvhs', 'dth_string', dth_string,
                "study_instance_uid = '%s' and roi_name = '%s'" %
                (study_instance_uid, roi_name))
        except:
            print('dist_to_ptv calculation failure, skipping')
Exemple #11
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)'

                    planes = get_planes_from_string(roi_coord_str)
                    centroid = calc_centroid(planes)
                    spread = calc_spread(planes)
                    cross_sections = calc_cross_section(planes)

                    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,
                        ','.join(['%.3f' % num for num in centroid
                                  ]), spread[0], spread[1], spread[2],
                        cross_sections['max'], cross_sections['median'])
                    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])