def median_profiles(self): """Return two median profiles from the open and dmlc image. For visual comparison.""" # dmlc median profile dmlc_prof = SingleProfile(np.median(self.image_dmlc, axis=0)) dmlc_prof.stretch() # open median profile open_prof = SingleProfile(np.median(self.image_open, axis=0)) open_prof.stretch() # normalize the profiles to near the same value norm_val = np.percentile(dmlc_prof.values, 90) dmlc_prof.normalize(norm_val) norm_val = np.percentile(open_prof.values, 90) open_prof.normalize(norm_val) return dmlc_prof, open_prof
def flatsym_helper(args): calc_definition = args["calc_definition"] center_definition = args["center_definition"] center_x = args["center_x"] center_y = args["center_y"] invert = args["invert"] w = args["instance"] station = args["station"] imgdescription = args["imgdescription"] displayname = args["displayname"] acquisition_datetime = args["acquisition_datetime"] general_functions.set_configuration( args["config"]) # Transfer to this process # Collect data for "save results" dicomenergy = general_functions.get_energy_from_imgdescription( imgdescription) user_machine, user_energy = general_functions.get_user_machine_and_energy( station, dicomenergy) machines_and_energies = general_functions.get_machines_and_energies( general_functions.get_treatmentunits_flatsym()) tolerances = general_functions.get_tolerance_user_machine_flatsym( user_machine) # If user_machne has specific tolerance if not tolerances: tolerance_flat, tolerance_sym, pdf_report_enable = general_functions.get_settings_flatsym( ) else: tolerance_flat, tolerance_sym, pdf_report_enable = tolerances[0] tolerance_flat = float(tolerance_flat) tolerance_sym = float(tolerance_sym) save_results = { "user_machine": user_machine, "user_energy": user_energy, "machines_and_energies": machines_and_energies, "displayname": displayname } temp_folder, file_path = RestToolbox.GetSingleDcm(config.ORTHANC_URL, w) try: flatsym = FlatSym(file_path) except Exception as e: return template("error_template", { "error_message": "The FlatSym module cannot calculate. " + str(e) }) # Define the center pixel where to get profiles: def find_field_centroid(img): '''taken from pylinac WL module''' min, max = np.percentile(img.image.array, [5, 99.9]) # min, max = np.amin(img.array), np.max(img.array) threshold_img = img.image.as_binary((max - min) / 2 + min) # clean single-pixel noise from outside field coords = ndimage.measurements.center_of_mass(threshold_img) return (int(coords[-1]), int(coords[0])) flatsym.image.crop(pixels=2) flatsym.image.check_inversion() if invert: flatsym.image.invert() flatsym.image.array = np.flipud(flatsym.image.array) vmax = flatsym.image.array.max() if center_definition == "Automatic": center_int = [ int(flatsym.image.array.shape[1] / 2), int(flatsym.image.array.shape[0] / 2) ] center = [0.5, 0.5] elif center_definition == "CAX": center_int = find_field_centroid( flatsym) # Define as mechanical isocenter center = [ int(center_int[0]) / flatsym.image.array.shape[1], int(center_int[1]) / flatsym.image.array.shape[0] ] else: center_int = [int(center_x), int(center_y)] center = [ int(center_x) / flatsym.image.array.shape[1], int(center_y) / flatsym.image.array.shape[0] ] fig = Figure(figsize=(9, 9), tight_layout={"w_pad": 1}) ax = fig.add_subplot(1, 1, 1) ax.imshow(flatsym.image.array, cmap=matplotlib.cm.jet, interpolation="none", vmin=0.9 * vmax, vmax=vmax, aspect="equal", origin='lower') ax.autoscale(tight=True) # Plot lines along which the profiles are calculated: ax.plot([0, flatsym.image.array.shape[1]], [center_int[1], center_int[1]], "b-", linewidth=2) ax.plot([center_int[0], center_int[0]], [0, flatsym.image.array.shape[0]], c="darkgreen", linestyle="-", linewidth=2) ax.set_xlim([0, flatsym.image.array.shape[1]]) ax.set_ylim([0, flatsym.image.array.shape[0]]) # Get profiles crossplane = PylinacSingleProfile(flatsym.image.array[center_int[1], :]) inplane = PylinacSingleProfile(flatsym.image.array[:, center_int[0]]) # Do some filtering: crossplane.filter(kind='median', size=0.01) inplane.filter(kind='median', size=0.01) # Normalize profiles norm_val_crossplane = crossplane.values[center_int[0]] norm_val_inplane = inplane.values[center_int[1]] crossplane.normalize(norm_val=norm_val_crossplane) inplane.normalize(norm_val=norm_val_inplane) # Get index of CAX of both profiles(different than center) to be used for mirroring: fwhm_crossplane = crossplane.fwxm_center(interpolate=True) fwhm_inplane = inplane.fwxm_center(interpolate=True) # Plot profiles divider = make_axes_locatable(ax) ax_crossplane = divider.append_axes("bottom", size="40%", pad=0.25, sharex=ax) ax_crossplane.set_xlim([0, flatsym.image.array.shape[1]]) ax_crossplane.set_xticks([]) ax_crossplane.set_title("Crossplane") ax_inplane = divider.append_axes("right", size="40%", pad=0.25, sharey=ax) ax_inplane.set_ylim([0, flatsym.image.array.shape[0]]) ax_inplane.set_yticks([]) ax_inplane.set_title("Inplane") ax_crossplane.plot(crossplane._indices, crossplane, "b-") ax_crossplane.plot(2 * fwhm_crossplane - crossplane._indices, crossplane, "b--") ax_inplane.plot(inplane, inplane._indices, c="darkgreen", linestyle="-") ax_inplane.plot(inplane, 2 * fwhm_inplane - inplane._indices, c="darkgreen", linestyle="--") ax_inplane.grid(alpha=0.5) ax_crossplane.grid(alpha=0.5) mpld3.plugins.connect(fig, mpld3.plugins.MousePosition(fontsize=14, fmt=".2f")) script = mpld3.fig_to_html(fig, d3_url=D3_URL, mpld3_url=MPLD3_URL) if calc_definition == "Elekta": method = "elekta" else: method = "varian" try: flatsym.analyze(flatness_method=method, symmetry_method=method, vert_position=center[0], horiz_position=center[1]) except Exception as e: return template("error_template", {"error_message": "Analysis failed. " + str(e)}) symmetry_hor = round(flatsym.symmetry['horizontal']['value'], 2) symmetry_vrt = round(flatsym.symmetry['vertical']['value'], 2) flatness_hor = round(flatsym.flatness['horizontal']['value'], 2) flatness_vrt = round(flatsym.flatness['vertical']['value'], 2) horizontal_width = round( flatsym.symmetry['horizontal']['profile'].fwxm(interpolate=True) / flatsym.image.dpmm, 2) vertical_width = round( flatsym.symmetry['vertical']['profile'].fwxm(interpolate=True) / flatsym.image.dpmm, 2) horizontal_penumbra_width = round( flatsym.symmetry['horizontal']['profile'].penumbra_width( interpolate=True) / flatsym.image.dpmm, 2) vertical_penumbra_width = round( flatsym.symmetry['vertical']['profile'].penumbra_width( interpolate=True) / flatsym.image.dpmm, 2) # Check if passed if method == "varian": if (flatness_hor < tolerance_flat) and (flatness_vrt < tolerance_flat) and ( symmetry_hor < tolerance_sym) and (symmetry_vrt < tolerance_sym): passed = True else: passed = False else: if (abs(flatness_hor - 100) < tolerance_flat) and ( abs(flatness_vrt - 100) < tolerance_flat) and ( abs(symmetry_hor - 100) < tolerance_sym) and ( abs(symmetry_vrt - 100) < tolerance_sym): passed = True else: passed = False variables = { "symmetry_hor": symmetry_hor, "symmetry_vrt": symmetry_vrt, "flatness_hor": flatness_hor, "flatness_vrt": flatness_vrt, "horizontal_width": horizontal_width, "vertical_width": vertical_width, "horizontal_penumbra_width": horizontal_penumbra_width, "vertical_penumbra_width": vertical_penumbra_width, "passed": passed, "pdf_report_enable": pdf_report_enable, "script": script, "save_results": save_results, "acquisition_datetime": acquisition_datetime, "calc_definition": calc_definition } # Generate pylinac report: if pdf_report_enable == "True": pdf_file = tempfile.NamedTemporaryFile(delete=False, prefix="FlatSym", suffix=".pdf", dir=config.PDF_REPORT_FOLDER) flatsym.publish_pdf(pdf_file) variables["pdf_report_filename"] = os.path.basename(pdf_file.name) general_functions.delete_files_in_subfolders([temp_folder]) # Delete image return template("flatsym_results", variables)