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')
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])