def planar_imaging_start(): colormaps = ["gray", "Greys", "brg", "prism"] displayname = request.forms.hidden_displayname username = request.get_cookie("account", secret=config.SECRET_KEY) if not username: redirect("/login") try: variables = general_functions.Read_from_dcm_database() except ConnectionError: return template( "error_template", {"error_message": "Orthanc is " "refusing connection."}) variables["displayname"] = displayname response.set_cookie("account", username, secret=config.SECRET_KEY, samesite="lax") variables["colormaps"] = colormaps # Get list of machines/beams/phantoms from the database machines_and_beams = {} for k in config.PLANARIMAGING_PHANTOMS: machines_and_beams[k] = general_functions.get_machines_and_energies( general_functions.get_treatmentunits_planarimaging(k)) variables["machines_beams_phantoms"] = machines_and_beams return template("planar_imaging", variables)
def starshot_module(): displayname = request.forms.hidden_displayname username = request.get_cookie("account", secret=config.SECRET_KEY) if not username: redirect("/login") try: variables = general_functions.Read_from_dcm_database() variables["displayname"] = displayname response.set_cookie("account", username, secret=config.SECRET_KEY, samesite="lax") except ConnectionError: return template("error_template", {"error_message": "Orthanc is refusing connection."}) return template("starshot", variables)
def image_review(): colormaps = ["Greys", "gray", "brg", "prism"] displayname = request.forms.hidden_displayname username = request.get_cookie("account", secret=config.SECRET_KEY) if not username: redirect("/login") try: variables = general_functions.Read_from_dcm_database() variables["colormaps"] = colormaps variables["displayname"] = displayname response.set_cookie("account", username, secret=config.SECRET_KEY, samesite="lax") except ConnectionError: return template("error_template", {"error_message": "Orthanc is refusing connection."}) return template("image_review", variables)
def administration(): username = request.get_cookie("account", secret=config.SECRET_KEY) displayname = request.forms.hidden_displayname if not username: redirect("/login") elif not general_functions.check_is_admin(username): return template("error_template", {"error_message": "Insufficient rights."}) else: variables = {"displayname": displayname} response.set_cookie("account", username, secret=config.SECRET_KEY, samesite="lax") return template("administration", variables)
def starshot_calculate(imgtype, w): # w is the image clip_box = float(request.forms.hidden_clipbox)*10.0 radius = float(request.forms.hidden_radius) min_peak_height = float(request.forms.hidden_mph) start_x = int(request.forms.hidden_px) start_y = int(request.forms.hidden_py) dpi = int(request.forms.hidden_dpi) sid = float(request.forms.hidden_sid) imgdescription = request.forms.hidden_imgdescription station = request.forms.hidden_station displayname = request.forms.hidden_displayname acquisition_datetime = request.forms.hidden_datetime fwhm = True if request.forms.hidden_fwhm=="true" else False recursive = True if request.forms.hidden_recursive=="true" else False invert = True if request.forms.hidden_invert=="true" else False # Get either dicom or non-dicom file if imgtype == "dicom": temp_folder, file_path = RestToolbox.GetSingleDcm(config.ORTHANC_URL, w) else: if request.files.get("input_nondicom_file") is not None: upload = request.files.get("input_nondicom_file") if os.path.splitext(upload.filename)[1] == ".tif": temp_folder = tempfile.mkdtemp(prefix=os.path.splitext(upload.filename)[0]+"_", dir=config.TEMP_NONDCM_FOLDER) file_path = os.path.join(temp_folder, upload.filename) with open(file_path, "wb") as dst: upload.save(dst, overwrite=False) dst.close() else: return template("error_template", {"error_message": "Please load a valid image file."}) else: return template("error_template", {"error_message": "Please load a valid image file."}) args = {"imgtype": imgtype, "w": w, "clip_box": clip_box, "radius":radius, "min_peak_height":min_peak_height, "start_x": start_x, "start_y":start_y, "dpi":dpi, "sid":sid, "fwhm":fwhm,"recursive":recursive, "invert":invert, "temp_folder": temp_folder, "file_path":file_path, "imgdescription": imgdescription, "station": station, "displayname": displayname, "acquisition_datetime": acquisition_datetime, "config": general_functions.get_configuration()} p = Pool(1) data = p.map(starshot_helperf_catch_error, [args]) p.close() p.join() return data
def login_submit(): username = request.forms.username password = request.forms.password user_list = get_one_user(username) if user_list is None: return template("error_template.tpl", error_message="User not recognized.") else: if not check_encrypted_password(password, user_list["Password"]): return template("error_template.tpl", error_message="Wrong password.") else: response.set_cookie("account", username, secret=config.SECRET_KEY, samesite="lax") return template("menu_page.tpl", institution=config.INSTITUTION, orthanc_url=config.ORTHANC_URL, qaserver_version=config.QASERVER_VERSION, displayname=user_list["DisplayName"], is_admin=check_is_admin(username))
def login_form(): images = [] for f in os.listdir(os.path.join(CUR_DIR, "static", "images")): if f.endswith('.png'): images.append(os.path.join("images", f)) if images: image = random.choice(images) else: image = "blank" return template("login.tpl", institution=config.INSTITUTION, image=image)
def review_trends(): displayname = request.forms.hidden_displayname username = request.get_cookie("account", secret=config.SECRET_KEY) if not username: redirect("/login") tables = { "Winston Lutz": WINSTON_LUTZ_PARAMETERS, "Starshot": STARSHOT_PARAMETERS, "Picketfence": PICKETFENCE_PARAMETERS, "PlanarImaging": PLANARIMAGING_PARAMETERS, "Catphan": CATPHAN_PARAMETERS, "Flatness/Symmetry": FLATSYM_PARAMETERS, "Vmat": VMAT_PARAMETERS, "Fieldsize": FIELDSIZE_PARAMETERS, "Fieldrot": FIELDROTATION_PARAMETERS } unique_names = { "Winston Lutz": get_unique_names("WinstonlutzUniqueNames"), "Starshot": get_unique_names("StarshotUniqueNames"), "Picketfence": get_unique_names("PicketfenceUniqueNames"), "PlanarImaging": get_unique_names("PlanarImagingUniqueNames"), "Catphan": get_unique_names("CatphanUniqueNames"), "Flatness/Symmetry": get_unique_names("FlatSymUniqueNames"), "Vmat": get_unique_names("VmatUniqueNames"), "Fieldsize": get_unique_names("FieldSizeUniqueNames"), "Fieldrot": get_unique_names("FieldRotationUniqueNames") } variables = { "tables": json.dumps(tables), "unique_names": json.dumps(unique_names), "displayname": displayname, "is_admin": general_functions.check_is_admin(username) } response.set_cookie("account", username, secret=config.SECRET_KEY, samesite="lax") return template("trends", variables)
def catphan_calculate_helperf_catch_error(args): try: return catphan_calculate_helperf(args) except Exception as e: return template("error_template", {"error_message": str(e)})
def edit_settings_fieldsize(): variables = {"field_sizes": config.FIELDSIZE_FIELDS} return template("edit_settings_fieldsize", variables)
def planar_imaging_helperf(args): # This function is used in order to prevent memory problems clip_box = args["clip_box"] phantom = args["phantom"] machine = args["machine"] beam = args["beam"] leedsrot1 = args["leedsrot1"] leedsrot2 = args["leedsrot2"] inv = args["inv"] bbox = args["bbox"] w1 = args["w1"] use_reference = args["use_reference"] colormap = args["colormap"] displayname = args["displayname"] acquisition_datetime = args["acquisition_datetime"] general_functions.set_configuration( args["config"]) # Transfer to this process # Collect data for "save results" tolerances = general_functions.get_tolerance_user_machine_planarimaging( machine, beam, phantom) # If user_machne has specific tolerance if not tolerances: lowtresh, hightresh, generate_pdf = 0.05, 0.1, "True" else: lowtresh, hightresh, generate_pdf = tolerances lowtresh = float(lowtresh) hightresh = float(hightresh) # Set colormap cmap = matplotlib.cm.get_cmap(colormap) try: temp_folder1, file_path1 = RestToolbox.GetSingleDcm( config.ORTHANC_URL, w1) except: return template("error_template", {"error_message": "Cannot read image."}) ref_path1 = general_functions.get_referenceimagepath_planarimaging( machine, beam, phantom) if ref_path1 is not None: ref_path1 = os.path.join(config.REFERENCE_IMAGES_FOLDER, ref_path1[0]) if os.path.exists(ref_path1): ref1_exists = True else: ref1_exists = False else: ref1_exists = False if not use_reference: ref1_exists = False # First analyze first image try: if phantom == "QC3": pi1 = StandardImagingQC3(file_path1) elif phantom == "LeedsTOR": pi1 = LeedsTOR(file_path1) elif phantom == "Las Vegas": pi1 = LasVegas(file_path1) elif phantom == "DoselabMC2MV": pi1 = DoselabMC2MV(file_path1) else: pi1 = DoselabMC2kV(file_path1) if clip_box != 0: try: #pi1.image.check_inversion_by_histogram() general_functions.clip_around_image(pi1.image, clip_box) except Exception as e: return template( "error_template", {"error_message": "Unable to apply clipbox. " + str(e)}) pi1.analyze(low_contrast_threshold=lowtresh, high_contrast_threshold=hightresh, invert=inv, angle_override=None if leedsrot2 == 0 else leedsrot2) except Exception as e: return template("error_template", {"error_message": "Cannot analyze image 1. " + str(e)}) # Analyze reference images if they exists if ref1_exists: try: if phantom == "QC3": ref1 = StandardImagingQC3(ref_path1) elif phantom == "LeedsTOR": ref1 = LeedsTOR(ref_path1) elif phantom == "Las Vegas": ref1 = LasVegas(ref_path1) elif phantom == "DoselabMC2MV": ref1 = DoselabMC2MV(ref_path1) else: ref1 = DoselabMC2kV(ref_path1) if clip_box != 0: try: #ref1.image.check_inversion_by_histogram() general_functions.clip_around_image(ref1.image, clip_box) except Exception as e: return template("error_template", { "error_message": "Unable to apply clipbox. " + str(e) }) ref1.analyze(low_contrast_threshold=lowtresh, high_contrast_threshold=hightresh, invert=inv, angle_override=None if leedsrot1 == 0 else leedsrot1) except: return template("error_template", {"error_message": "Cannot analyze reference image."\ " Check that the image in the database is valid."}) save_results = { "machine": machine, "beam": beam, "phantom": phantom, "displayname": displayname } fig = Figure(figsize=(10.5, 5), tight_layout={"w_pad": 0, "pad": 1.5}) ax_ref = fig.add_subplot(1, 2, 1) ax_pi = fig.add_subplot(1, 2, 2) # Plot reference image and regions if phantom == "QC3": low_contrast_rois_pi1 = pi1.low_contrast_rois[ 1:] # Exclude first point which is background else: low_contrast_rois_pi1 = pi1.low_contrast_rois if ref1_exists: if phantom == "QC3": low_contrast_rois_ref1 = ref1.low_contrast_rois[ 1:] # Exclude first point which is background else: low_contrast_rois_ref1 = ref1.low_contrast_rois if ref1_exists: ax_ref.imshow(ref1.image.array, cmap=cmap, interpolation="none", aspect="equal", origin='upper') ax_ref.set_title(phantom + ' Reference Image') ax_ref.axis('off') # plot the background ROIS for roi in ref1.low_contrast_background_rois: roi.plot2axes(ax_ref, edgecolor='yellow') ax_ref.text(roi.center.x, roi.center.y, "B", horizontalalignment='center', verticalalignment='center') # low contrast ROIs for ind, roi in enumerate(low_contrast_rois_ref1): roi.plot2axes(ax_ref, edgecolor=roi.plot_color) ax_ref.text(roi.center.x, roi.center.y, str(ind), horizontalalignment='center', verticalalignment='center') # plot the high-contrast ROIs if phantom != "Las Vegas": mtf_temp_ref = list(ref1.mtf.norm_mtfs.values()) for ind, roi in enumerate(ref1.high_contrast_rois): color = 'b' if mtf_temp_ref[ ind] > ref1._high_contrast_threshold else 'r' roi.plot2axes(ax_ref, edgecolor=color) ax_ref.text(roi.center.x, roi.center.y, str(ind), horizontalalignment='center', verticalalignment='center') else: ax_ref.text(0.5, 0.5, "Reference image not available", horizontalalignment='center', verticalalignment='center') # Plot current image and regions ax_pi.imshow(pi1.image.array, cmap=cmap, interpolation="none", aspect="equal", origin='upper') ax_pi.axis('off') ax_pi.set_title(phantom + ' Current Image') # plot the background ROIS for roi in pi1.low_contrast_background_rois: roi.plot2axes(ax_pi, edgecolor='yellow') ax_pi.text(roi.center.x, roi.center.y, "B", horizontalalignment='center', verticalalignment='center') # low contrast ROIs for ind, roi in enumerate(low_contrast_rois_pi1): roi.plot2axes(ax_pi, edgecolor=roi.plot_color) ax_pi.text(roi.center.x, roi.center.y, str(ind), horizontalalignment='center', verticalalignment='center') # plot the high-contrast ROIs if phantom != "Las Vegas": mtf_temp_pi = list(pi1.mtf.norm_mtfs.values()) for ind, roi in enumerate(pi1.high_contrast_rois): color = 'b' if mtf_temp_pi[ ind] > pi1._high_contrast_threshold else 'r' roi.plot2axes(ax_pi, edgecolor=color) ax_pi.text(roi.center.x, roi.center.y, str(ind), horizontalalignment='center', verticalalignment='center') # Zoom on phantom if requested: if bbox: if phantom == "QC3" or phantom == "DoselabMC2MV" or phantom == "DoselabMC2kV": pad = 15 # Additional space between cyan bbox and plot if ref1_exists: bounding_box_ref = ref1.phantom_ski_region.bbox bbox_center_ref = ref1.phantom_center if abs(bounding_box_ref[1] - bounding_box_ref[3]) >= abs(bounding_box_ref[2] - bounding_box_ref[0]): dist = abs(bounding_box_ref[1] - bounding_box_ref[3]) / 2 ax_ref.set_ylim(bbox_center_ref.y + dist + pad, bbox_center_ref.y - dist - pad) ax_ref.set_xlim(bbox_center_ref.x - dist - pad, bbox_center_ref.x + dist + pad) else: dist = abs(bounding_box_ref[2] - bounding_box_ref[0]) / 2 ax_ref.set_ylim(bbox_center_ref.y + dist + pad, bbox_center_ref.y - dist - pad) ax_ref.set_xlim(bbox_center_ref.x - dist - pad, bbox_center_ref.x + dist + pad) ax_ref.plot([ bounding_box_ref[1], bounding_box_ref[1], bounding_box_ref[3], bounding_box_ref[3], bounding_box_ref[1] ], [ bounding_box_ref[2], bounding_box_ref[0], bounding_box_ref[0], bounding_box_ref[2], bounding_box_ref[2] ], c="cyan") ax_ref.autoscale(False) bounding_box_pi = pi1.phantom_ski_region.bbox bbox_center_pi = pi1.phantom_center if abs(bounding_box_pi[1] - bounding_box_pi[3]) >= abs(bounding_box_pi[2] - bounding_box_pi[0]): dist = abs(bounding_box_pi[1] - bounding_box_pi[3]) / 2 ax_pi.set_ylim(bbox_center_pi.y + dist + pad, bbox_center_pi.y - dist - pad) ax_pi.set_xlim(bbox_center_pi.x - dist - pad, bbox_center_pi.x + dist + pad) else: dist = abs(bounding_box_pi[2] - bounding_box_pi[0]) / 2 ax_pi.set_ylim(bbox_center_pi.y + dist + pad, bbox_center_pi.y - dist - pad) ax_pi.set_xlim(bbox_center_pi.x - dist - pad, bbox_center_pi.x + dist + pad) ax_pi.plot([ bounding_box_pi[1], bounding_box_pi[1], bounding_box_pi[3], bounding_box_pi[3], bounding_box_pi[1] ], [ bounding_box_pi[2], bounding_box_pi[0], bounding_box_pi[0], bounding_box_pi[2], bounding_box_pi[2] ], c="cyan") ax_pi.autoscale(False) elif phantom == "Las Vegas": # For some reason phantom_ski_regio has an underscore pad = 15 # Additional space between cyan bbox and plot if ref1_exists: bounding_box_ref = ref1._phantom_ski_region.bbox bbox_center_ref = ref1.phantom_center if abs(bounding_box_ref[1] - bounding_box_ref[3]) >= abs(bounding_box_ref[2] - bounding_box_ref[0]): dist = abs(bounding_box_ref[1] - bounding_box_ref[3]) / 2 ax_ref.set_ylim(bbox_center_ref.y + dist + pad, bbox_center_ref.y - dist - pad) ax_ref.set_xlim(bbox_center_ref.x - dist - pad, bbox_center_ref.x + dist + pad) else: dist = abs(bounding_box_ref[2] - bounding_box_ref[0]) / 2 ax_ref.set_ylim(bbox_center_ref.y + dist + pad, bbox_center_ref.y - dist - pad) ax_ref.set_xlim(bbox_center_ref.x - dist - pad, bbox_center_ref.x + dist + pad) ax_ref.plot([ bounding_box_ref[1], bounding_box_ref[1], bounding_box_ref[3], bounding_box_ref[3], bounding_box_ref[1] ], [ bounding_box_ref[2], bounding_box_ref[0], bounding_box_ref[0], bounding_box_ref[2], bounding_box_ref[2] ], c="cyan") ax_ref.autoscale(False) bounding_box_pi = pi1._phantom_ski_region.bbox bbox_center_pi = pi1.phantom_center if abs(bounding_box_pi[1] - bounding_box_pi[3]) >= abs(bounding_box_pi[2] - bounding_box_pi[0]): dist = abs(bounding_box_pi[1] - bounding_box_pi[3]) / 2 ax_pi.set_ylim(bbox_center_pi.y + dist + pad, bbox_center_pi.y - dist - pad) ax_pi.set_xlim(bbox_center_pi.x - dist - pad, bbox_center_pi.x + dist + pad) else: dist = abs(bounding_box_pi[2] - bounding_box_pi[0]) / 2 ax_pi.set_ylim(bbox_center_pi.y + dist + pad, bbox_center_pi.y - dist - pad) ax_pi.set_xlim(bbox_center_pi.x - dist - pad, bbox_center_pi.x + dist + pad) ax_pi.plot([ bounding_box_pi[1], bounding_box_pi[1], bounding_box_pi[3], bounding_box_pi[3], bounding_box_pi[1] ], [ bounding_box_pi[2], bounding_box_pi[0], bounding_box_pi[0], bounding_box_pi[2], bounding_box_pi[2] ], c="cyan") ax_pi.autoscale(False) elif phantom == "LeedsTOR": pad = 15 # Additional space between cyan bbox and plot if ref1_exists: big_circle_idx = np.argsort([ ref1._regions[roi].major_axis_length for roi in ref1._blobs ])[-1] circle_roi = ref1._regions[ref1._blobs[big_circle_idx]] bounding_box_ref = circle_roi.bbox bbox_center_ref = bbox_center(circle_roi) max_xy = max([ abs(bounding_box_ref[1] - bounding_box_ref[3]) / 2, abs(bounding_box_ref[0] - bounding_box_ref[2]) / 2 ]) ax_ref.set_ylim(bbox_center_ref.y + max_xy + pad, bbox_center_ref.y - max_xy - pad) ax_ref.set_xlim(bbox_center_ref.x - max_xy - pad, bbox_center_ref.x + max_xy + pad) ax_ref.plot([ bounding_box_ref[1], bounding_box_ref[1], bounding_box_ref[3], bounding_box_ref[3], bounding_box_ref[1] ], [ bounding_box_ref[2], bounding_box_ref[0], bounding_box_ref[0], bounding_box_ref[2], bounding_box_ref[2] ], c="cyan") ax_ref.autoscale(False) big_circle_idx = np.argsort([ pi1._regions[roi].major_axis_length for roi in pi1._blobs ])[-1] circle_roi = pi1._regions[pi1._blobs[big_circle_idx]] bounding_box_pi = circle_roi.bbox bbox_center_pi = bbox_center(circle_roi) max_xy = max([ abs(bounding_box_pi[1] - bounding_box_pi[3]) / 2, abs(bounding_box_pi[0] - bounding_box_pi[2]) / 2 ]) ax_pi.set_ylim(bbox_center_pi.y + max_xy + pad, bbox_center_pi.y - max_xy - pad) ax_pi.set_xlim(bbox_center_pi.x - max_xy - pad, bbox_center_pi.x + max_xy + pad) ax_pi.plot([ bounding_box_pi[1], bounding_box_pi[1], bounding_box_pi[3], bounding_box_pi[3], bounding_box_pi[1] ], [ bounding_box_pi[2], bounding_box_pi[0], bounding_box_pi[0], bounding_box_pi[2], bounding_box_pi[2] ], c="cyan") ax_pi.autoscale(False) # Add phantom outline: outline_obj_pi1, settings_pi1 = pi1._create_phantom_outline_object() outline_obj_pi1.plot2axes(ax_pi, edgecolor='g', **settings_pi1) if ref1_exists: outline_obj_ref1, settings_ref1 = ref1._create_phantom_outline_object() outline_obj_ref1.plot2axes(ax_ref, edgecolor='g', **settings_ref1) # Plot low frequency contrast, CNR and rMTF fig2 = Figure(figsize=(10.5, 10), tight_layout={"w_pad": 1}) ax_lfc = fig2.add_subplot(2, 2, 1) ax_lfcnr = fig2.add_subplot(2, 2, 2) ax_rmtf = fig2.add_subplot(2, 2, 3) # lfc ax_lfc.plot([abs(roi.contrast) for roi in low_contrast_rois_pi1], marker='o', markersize=8, color='r') if ref1_exists: ax_lfc.plot([abs(roi.contrast) for roi in low_contrast_rois_ref1], marker='o', color='r', markersize=8, markerfacecolor="None", linestyle="--") ax_lfc.plot([], [], color='r', linestyle="--", label='Reference') ax_lfc.plot([], [], color='r', label='Current') ax_lfc.plot([0, len(low_contrast_rois_pi1) - 1], [lowtresh, lowtresh], "-g") ax_lfc.grid(True) ax_lfc.set_title('Low-frequency Contrast') ax_lfc.set_xlabel('ROI #') ax_lfc.set_ylabel('Contrast') ax_lfc.set_xticks(np.arange(0, len(low_contrast_rois_pi1), 1)) ax_lfc.legend(loc='upper right', ncol=2, columnspacing=0, fontsize=12, handletextpad=0) ax_lfc.margins(0.05) # CNR ax_lfcnr.plot( [abs(roi.contrast_to_noise) for roi in low_contrast_rois_pi1], marker='^', markersize=8, color='r') if ref1_exists: ax_lfcnr.plot( [abs(roi.contrast_to_noise) for roi in low_contrast_rois_ref1], marker='^', color='r', markersize=8, markerfacecolor="None", linestyle="--") ax_lfcnr.plot([], [], color='r', linestyle="--", label='Reference') ax_lfcnr.plot([], [], color='r', label='Current') ax_lfcnr.grid(True) ax_lfcnr.set_title('Contrast-Noise Ratio') ax_lfcnr.set_xlabel('ROI #') ax_lfcnr.set_ylabel('CNR') ax_lfcnr.set_xticks(np.arange(0, len(low_contrast_rois_pi1), 1)) ax_lfcnr.legend(loc='upper right', ncol=2, columnspacing=0, fontsize=12, handletextpad=0) ax_lfcnr.margins(0.05) # rMTF if phantom != "Las Vegas": mtfs_pi1 = list(pi1.mtf.norm_mtfs.values()) if ref1_exists: mtfs_ref1 = list(ref1.mtf.norm_mtfs.values()) else: mtfs_ref1 = [np.nan] * len(mtfs_pi1) lppmm = pi1.mtf.spacings ax_rmtf.plot(lppmm, mtfs_pi1, marker='D', markersize=8, color='b') ax_rmtf.plot([min(lppmm), max(lppmm)], [hightresh, hightresh], "-g") if ref1_exists: ax_rmtf.plot(lppmm, mtfs_ref1, marker='D', color='b', markersize=8, markerfacecolor="None", linestyle="--") ax_rmtf.plot([], [], color='b', linestyle="--", label='Reference') ax_rmtf.plot([], [], color='b', label='Current') ax_rmtf.grid(True) ax_rmtf.set_title('High-frequency rMTF') ax_rmtf.set_xlabel('Line pairs / mm') ax_rmtf.set_ylabel('relative MTF') ax_rmtf.legend(loc='upper right', ncol=2, columnspacing=0, fontsize=12, handletextpad=0) ax_rmtf.margins(0.05) f30 = [ ref1.mtf.relative_resolution(30) if ref1_exists else np.nan, pi1.mtf.relative_resolution(30) ] f40 = [ ref1.mtf.relative_resolution(40) if ref1_exists else np.nan, pi1.mtf.relative_resolution(40) ] f50 = [ ref1.mtf.relative_resolution(50) if ref1_exists else np.nan, pi1.mtf.relative_resolution(50) ] f80 = [ ref1.mtf.relative_resolution(80) if ref1_exists else np.nan, pi1.mtf.relative_resolution(80) ] else: ax_rmtf.text(0.5, 0.5, "MTF not available", horizontalalignment='center', verticalalignment='center') f30 = [np.nan, np.nan] f40 = [np.nan, np.nan] f50 = [np.nan, np.nan] f80 = [np.nan, np.nan] if ref1_exists: median_contrast = [ np.median([roi.contrast for roi in low_contrast_rois_ref1]), np.median([roi.contrast for roi in low_contrast_rois_pi1]) ] median_CNR = [ np.median( [roi.contrast_to_noise for roi in low_contrast_rois_ref1]), np.median([roi.contrast_to_noise for roi in low_contrast_rois_pi1]) ] phantom_angle = [ref1.phantom_angle, pi1.phantom_angle] else: median_contrast = [ np.nan, np.median([roi.contrast for roi in low_contrast_rois_pi1]) ] median_CNR = [ np.nan, np.median([roi.contrast_to_noise for roi in low_contrast_rois_pi1]) ] phantom_angle = [np.nan, pi1.phantom_angle] script = mpld3.fig_to_html(fig, d3_url=D3_URL, mpld3_url=MPLD3_URL) script2 = mpld3.fig_to_html(fig2, d3_url=D3_URL, mpld3_url=MPLD3_URL) variables = { "script": script, "script2": script2, "f30": f30, "f40": f40, "f50": f50, "f80": f80, "median_contrast": median_contrast, "median_CNR": median_CNR, "pdf_report_enable": generate_pdf, "save_results": save_results, "acquisition_datetime": acquisition_datetime, "phantom_angle": phantom_angle } if generate_pdf == "True": pdf_file = tempfile.NamedTemporaryFile(delete=False, prefix="PlanarImaging_", suffix=".pdf", dir=config.PDF_REPORT_FOLDER) metadata = RestToolbox.GetInstances(config.ORTHANC_URL, [w1]) try: patient = metadata[0]["PatientName"] except: patient = "" try: stationname = metadata[0]["StationName"] except: stationname = "" try: date_time = RestToolbox.get_datetime(metadata[0]) date_var = datetime.datetime.strptime( date_time[0], "%Y%m%d").strftime("%d/%m/%Y") except: date_var = "" pi1.publish_pdf(pdf_file, notes=[ "Date = " + date_var, "Patient = " + patient, "Station = " + stationname ]) variables["pdf_report_filename"] = os.path.basename(pdf_file.name) general_functions.delete_figure([fig, fig2]) general_functions.delete_files_in_subfolders([temp_folder1 ]) # Delete image #gc.collect() return template("planar_imaging_results", variables)
def edit_orthanc(): return template("edit_orthanc")
def custom500(error): return template("error_template.tpl", error_message="Cause unknown.")
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)
def edit_settings_dynalog(): return template("edit_settings_dynalog")
def edit_settings_fieldrotation(): return template("edit_settings_fieldrotation")
def edit_settings_catphan(): variables = {"phantoms": config.CATPHAN_PHANTOMS} return template("edit_settings_catphan", variables)
def edit_settings_picketfence(): return template("edit_settings_picketfence")
def fieldrot_helperf_catch_error(args): try: return fieldrot_helperf(args) except Exception as e: return template("error_template", {"error_message": str(e)})
def edit_settings_starshot(): return template("edit_settings_starshot")
def edit_institution(): return template("edit_institution")
def edit_settings_winstonlutz(): return template("edit_settings_winstonlutz")
def catphan_calculate_helperf(args): use_reference = args["use_reference"] phantom = args["phantom"] machine = args["machine"] beam = args["beam"] HU_delta = args["HU_delta"] colormap = args["colormap"] displayname = args["displayname"] acquisition_datetime = args["acquisition_datetime"] s = args["s"] general_functions.set_configuration(args["config"]) # Transfer to this process save_results = { "machine": machine, "beam": beam, "phantom": phantom, "displayname": displayname } # Set colormap cmap = matplotlib.cm.get_cmap(colormap) # Collect data for "save results" tolerances = general_functions.get_tolerance_user_machine_catphan(machine, beam, phantom) # If user_machne has specific tolerance if not tolerances: hu, lcv, scaling, thickness, lowcontrast, cnr, mtf, uniformityidx, pdf_report_enable = "100", "2", "0.5", "0.25", "1", "10", "10", "3", "False" else: hu, lcv, scaling, thickness, lowcontrast, cnr, mtf, uniformityidx, pdf_report_enable = tolerances hu_tolerance = float(hu) lcv_tolerance = float(lcv) scaling_tolerance = float(scaling) thickness_tolerance = float(thickness) low_contrast_tolerance = float(lowcontrast) cnr_threshold = float(cnr) mtf_tolerance = float(mtf) uniformityidx_tolerance = float(uniformityidx) ref_path = general_functions.get_referenceimagepath_catphan(machine, beam, phantom) if ref_path is not None: ref_path = os.path.join(config.REFERENCE_IMAGES_FOLDER, ref_path[0]) if os.path.exists(ref_path): ref_exists = True else: ref_exists = False else: ref_exists = False folder_path = RestToolbox.GetSeries2Folder2(config.ORTHANC_URL, s) # Use two threads to speedup the calculation (if ref exists) args_current = {"hu_tolerance": hu_tolerance, "scaling_tolerance": scaling_tolerance, "thickness_tolerance": thickness_tolerance, "cnr_threshold": cnr_threshold, "path": folder_path, "phantom": phantom, "low_contrast_tolerance": low_contrast_tolerance, "config": general_functions.get_configuration()} args_ref = {"hu_tolerance": hu_tolerance, "scaling_tolerance": scaling_tolerance, "thickness_tolerance": thickness_tolerance, "cnr_threshold": cnr_threshold, "path": ref_path, "phantom": phantom, "low_contrast_tolerance": low_contrast_tolerance, "config": general_functions.get_configuration()} if use_reference and ref_exists: try: p = ThreadPool(2) [mycbct, mycbct_ref] = p.map(catphan_helperf_analyze, [args_current, args_ref]) finally: p.close() p.join() else: mycbct = catphan_helperf_analyze(args_current) if use_reference and ref_exists: if isinstance(mycbct_ref, Exception): return template("error_template", {"error_message": "Unable to analyze reference image. " + str(mycbct_ref) }) if isinstance(mycbct, Exception): general_functions.delete_files_in_subfolders([folder_path]) # Delete temporary images return template("error_template", {"error_message": "Unable to analyze image. " + str(mycbct) }) try: # add this to prevent memory problems when threads with exceptions are still alive # ######################### CTP528 - Resolution ################################### fig_dcm = Figure(figsize=(10.5, 5), tight_layout={"w_pad":0, "pad": 1.5}) ax1 = fig_dcm.add_subplot(1,2,1) ax2 = fig_dcm.add_subplot(1,2,2) # Reference image array if use_reference and ref_exists: ax1.imshow(mycbct_ref.ctp528.image.array, cmap=cmap, interpolation="none", aspect="equal", origin='upper') ax1.autoscale(enable=False) else: ax1.text(0.5, 0.5 ,"Reference image not available", horizontalalignment='center', verticalalignment='center') # Analysed current array ax2.imshow(mycbct.ctp528.image.array, cmap=cmap, interpolation="none", aspect="equal", origin='upper') ax2.set_title('CTP528 current image') ax1.set_title('CTP528 reference image') ax2.autoscale(enable=False) # Plot rMTF and gather some data fig_mtf = Figure(figsize=(5, 5), tight_layout={"w_pad":2, "pad": 1}) ax_mtf = fig_mtf.add_subplot(1,1,1) msize = 8 if use_reference and ref_exists: ax_mtf.plot(list(mycbct_ref.ctp528.mtf.norm_mtfs.keys()), list(mycbct_ref.ctp528.mtf.norm_mtfs.values()), marker='o', color="blue", markersize=msize, markerfacecolor="None", linestyle="--") ax_mtf.plot(list(mycbct.ctp528.mtf.norm_mtfs.keys()), list(mycbct.ctp528.mtf.norm_mtfs.values()), marker='o', color="blue", markersize=msize) ax_mtf.margins(0.05) ax_mtf.grid('on') ax_mtf.set_xlabel('Line pairs / mm') ax_mtf.set_ylabel("Relative MTF") ax_mtf.set_title('Modulation transfer function') script_ctp528 = mpld3.fig_to_html(fig_dcm, d3_url=D3_URL, mpld3_url=MPLD3_URL) script_ctp528mtf = mpld3.fig_to_html(fig_mtf, d3_url=D3_URL, mpld3_url=MPLD3_URL) # Some data: mtf30_ref = mycbct_ref.ctp528.mtf.relative_resolution(30) if use_reference and ref_exists else np.nan mtf30 = mycbct.ctp528.mtf.relative_resolution(30) mtf50_ref = mycbct_ref.ctp528.mtf.relative_resolution(50) if use_reference and ref_exists else np.nan mtf50 = mycbct.ctp528.mtf.relative_resolution(50) mtf80_ref = mycbct_ref.ctp528.mtf.relative_resolution(80) if use_reference and ref_exists else np.nan mtf80 = mycbct.ctp528.mtf.relative_resolution(80) if use_reference and ref_exists: mtf_passing = True if abs(100*(mtf50-mtf50_ref)/mtf50_ref)<=mtf_tolerance else False else: mtf_passing = None # ####################### CTP404 - GEOMETRY HU LINEARITY #################### fig_404 = Figure(figsize=(10.5, 5), tight_layout={"w_pad":0, "pad": 1.5}) ax404_1 = fig_404.add_subplot(1,2,1) ax404_2 = fig_404.add_subplot(1,2,2) def ctp404_plotROI(mycbct, fig, axis): # Plot lines and circles - taken from pylinac # plot HU linearity ROIs for roi in mycbct.ctp404.hu_rois.values(): axis.add_patch(matplotlib.patches.Circle((roi.center.x, roi.center.y), edgecolor=roi.plot_color, radius=roi.radius, fill=False)) for roi in mycbct.ctp404.bg_hu_rois.values(): axis.add_patch(matplotlib.patches.Circle((roi.center.x, roi.center.y), edgecolor='blue', radius=roi.radius, fill=False)) # plot thickness ROIs for roi in mycbct.ctp404.thickness_rois.values(): axis.add_patch(matplotlib.patches.Rectangle((roi.bl_corner.x, roi.bl_corner.y), width=roi.width, height=roi.height, angle=0, edgecolor="blue", alpha=1, facecolor="g", fill=False)) # plot geometry lines for line in mycbct.ctp404.lines.values(): axis.plot((line.point1.x, line.point2.x), (line.point1.y, line.point2.y), linewidth=1, color=line.pass_fail_color) # Plot tooltips for patches names = [] hu_rois_centers_x = [] hu_rois_centers_y = [] hu_rois_radius = [] for name, roi in mycbct.ctp404.hu_rois.items(): names.append(name) hu_rois_centers_x.append(roi.center.x) hu_rois_centers_y.append(roi.center.y) hu_rois_radius.append((roi.radius)**2) hu_rois_ttip = axis.scatter(hu_rois_centers_x, hu_rois_centers_y, s = hu_rois_radius, alpha=0) labels = [names[i] for i in range(len(names))] tooltip = mpld3.plugins.PointLabelTooltip(hu_rois_ttip, labels=labels) mpld3.plugins.connect(fig, tooltip) # Add tooltips for 4 lines inc = 1 for line in mycbct.ctp404.lines.values(): hu_lines_ttip = axis.plot((line.point1.x, line.point2.x), (line.point1.y, line.point2.y), alpha=0, lw=7) tooltip2 = mpld3.plugins.LineLabelTooltip(hu_lines_ttip[0], label="Line "+str(inc)) mpld3.plugins.connect(fig, tooltip2) inc += 1 # Reference image if use_reference and ref_exists: ax404_1.imshow(mycbct_ref.ctp404.image.array, cmap=cmap, interpolation="none", aspect="equal", origin='upper') #mycbct_ref.ctp404.plot_rois(ax404_1) ctp404_plotROI(mycbct_ref, fig_404, ax404_1) # alternative ax404_1.autoscale(enable=False) ax404_1.set_xlim([0, mycbct_ref.ctp404.image.shape[1]]) ax404_1.set_ylim([mycbct_ref.ctp404.image.shape[0], 0]) else: ax404_1.text(0.5, 0.5 ,"Reference image not available", horizontalalignment='center', verticalalignment='center') # Current image ax404_2.imshow(mycbct.ctp404.image.array, cmap=cmap, interpolation="none", aspect="equal", origin='upper') ctp404_plotROI(mycbct, fig_404, ax404_2) # alternative #mycbct.ctp404.plot_rois(ax404_2) ax404_2.set_xlim([0, mycbct.ctp404.image.shape[1]]) ax404_2.set_ylim([mycbct.ctp404.image.shape[0], 0]) ax404_1.set_title('CTP404 reference image') ax404_2.set_title('CTP404 current image') ax404_2.autoscale(enable=False) # Draw HU linearity plot def plot_linearity(mycbct, fig, axis, plot_delta): '''Taken from pylinac''' nominal_x_values = [roi.nominal_val for roi in mycbct.ctp404.hu_rois.values()] actual_values = [] diff_values = [] if plot_delta: values = [] names = [] for name, roi in mycbct.ctp404.hu_rois.items(): names.append(name) values.append(roi.value_diff) actual_values.append(roi.pixel_value) diff_values.append(roi.value_diff) nominal_measurements = [0]*len(values) ylabel = 'HU Delta' else: values = [] names = [] for name, roi in mycbct.ctp404.hu_rois.items(): names.append(name) values.append(roi.pixel_value) actual_values.append(roi.pixel_value) diff_values.append(roi.value_diff) nominal_measurements = nominal_x_values ylabel = 'Measured Values' points = axis.plot(nominal_x_values, values, 'g+', markersize=15, mew=2) axis.plot(nominal_x_values, nominal_measurements) axis.plot(nominal_x_values, np.array(nominal_measurements) + mycbct.ctp404.hu_tolerance, 'r--') axis.plot(nominal_x_values, np.array(nominal_measurements) - mycbct.ctp404.hu_tolerance, 'r--') axis.margins(0.07) axis.grid(True, alpha=0.35) axis.set_xlabel("Nominal Values") axis.set_ylabel(ylabel) axis.set_title("HU linearity") labels = [names[i]+" -- Nom.={:.1f}, Act.={:.1f}, Diff.={:.1f}".format(nominal_x_values[i], actual_values[i], diff_values[i]) for i in range(len(names))] tooltip = mpld3.plugins.PointLabelTooltip(points[0], labels=labels, location="top right") mpld3.plugins.connect(fig, tooltip) fig_404_HU = Figure(figsize=(10.5, 5), tight_layout={"w_pad":1}) ax_HU_ref = fig_404_HU.add_subplot(1,2,1) ax_HU = fig_404_HU.add_subplot(1,2,2) # Reference HU linearity if use_reference and ref_exists: plot_linearity(mycbct_ref, fig_404_HU, ax_HU_ref, plot_delta=HU_delta) else: ax_HU_ref.text(0.5, 0.5 ,"Reference image not available", horizontalalignment='center', verticalalignment='center') ax_HU_ref.set_title("HU linearity") # Current HU linearity plot_linearity(mycbct, fig_404_HU, ax_HU, plot_delta=HU_delta) # Gather data from HU holes: if use_reference and ref_exists: HU_values_ref = [] HU_std_ref = [] HU_diff_ref = [] cnrs404_ref = [] for key, value in mycbct_ref.ctp404.hu_rois.items(): HU_values_ref.append(value.pixel_value) HU_std_ref.append(round(value.std, 1)) HU_diff_ref.append(value.value_diff) cnrs404_ref.append(round(value.cnr, 1)) # Background HU ROIs for key, value in mycbct_ref.ctp404.bg_hu_rois.items(): HU_values_ref.append(value.pixel_value) HU_std_ref.append(round(value.std, 1)) HU_diff_ref.append(np.nan) cnrs404_ref.append(np.nan) lcv_ref = round(mycbct_ref.ctp404.lcv, 2) slice_thickness_ref = round(mycbct_ref.ctp404.meas_slice_thickness, 2) lines_ref = [] # Line length for l in mycbct_ref.ctp404.lines.values(): lines_ref.append(round(l.length_mm, 2)) lines_avg_ref = round(mycbct_ref.ctp404.avg_line_length, 2) phantom_roll_ref = round(mycbct_ref.ctp404.catphan_roll, 2) dicom_slice_thickness_ref = round(mycbct_ref.ctp404.slice_thickness, 2) else: length = len(list(mycbct.ctp404.hu_rois.values())+list(mycbct.ctp404.bg_hu_rois.values())) HU_values_ref = [np.nan]*length HU_std_ref = [np.nan]*length HU_diff_ref = [np.nan]*length cnrs404_ref = [np.nan]*length lcv_ref = np.nan slice_thickness_ref = np.nan lines_ref = [np.nan]*len(mycbct.ctp404.lines.values()) lines_avg_ref = np.nan phantom_roll_ref = np.nan dicom_slice_thickness_ref = np.nan HU_values = [] HU_std = [] HU_diff = [] HU_nominal = [] HU_names = [] cnrs404 = [] HU_CNR_values_dict = {} for key, value in mycbct.ctp404.hu_rois.items(): HU_values.append(value.pixel_value) HU_std.append(round(value.std, 1)) HU_diff.append(value.value_diff) HU_nominal.append(value.nominal_val) HU_names.append(key) cnrs404.append(round(value.cnr, 1)) HU_CNR_values_dict[key] = [value.pixel_value, round(value.cnr, 1)] # Background HU ROIs for key, value in mycbct.ctp404.bg_hu_rois.items(): HU_values.append(value.pixel_value) HU_std.append(round(value.std, 1)) HU_diff.append(np.nan) HU_nominal.append(0) HU_names.append("Background "+str(key)) cnrs404.append(np.nan) HU_CNR_values_dict[key] = [value.pixel_value, "nan"] # For easier acces of values in results save_results["HU_CNR_values_dict"] = HU_CNR_values_dict lcv = mycbct.ctp404.lcv slice_thickness = round(mycbct.ctp404.meas_slice_thickness, 2) phantom_roll = round(mycbct.ctp404.catphan_roll, 2) dicom_slice_thickness = round(mycbct.ctp404.slice_thickness, 2) # Get origin slice and phantom center and slice number of other modules if use_reference and ref_exists: mm_per_pixel_ref = round(mycbct_ref.mm_per_pixel, 2) origin_slice_ref = mycbct_ref.origin_slice ctp528_slice_ref = mycbct_ref.ctp528.slice_num ctp486_slice_ref = mycbct_ref.ctp486.slice_num ctp515_slice_ref = mycbct_ref.ctp515.slice_num if phantom != "Catphan 503" else np.nan phantom_center_ref = [round(mycbct_ref.ctp404.phan_center.x, 2), round(mycbct_ref.ctp404.phan_center.y, 2)] else: mm_per_pixel_ref = np.nan origin_slice_ref = np.nan ctp528_slice_ref = np.nan ctp486_slice_ref = np.nan ctp515_slice_ref = np.nan phantom_center_ref = [np.nan, np.nan] mm_per_pixel = round(mycbct.mm_per_pixel, 2) origin_slice = mycbct.origin_slice ctp528_slice = mycbct.ctp528.slice_num ctp486_slice = mycbct.ctp486.slice_num ctp515_slice = mycbct.ctp515.slice_num if phantom != "Catphan 503" else np.nan phantom_center = [round(mycbct.ctp404.phan_center.x, 2), round(mycbct.ctp404.phan_center.y, 2)] lines = [] # Line length for l in mycbct.ctp404.lines.values(): lines.append(round(l.length_mm, 2)) lines_avg = round(mycbct.ctp404.avg_line_length, 2) passed_HU = mycbct.ctp404.passed_hu passed_thickness = mycbct.ctp404.passed_thickness passed_geometry = mycbct.ctp404.passed_geometry passed_lcv = True if lcv >= lcv_tolerance else False passed_404 = passed_HU and passed_thickness and passed_geometry and passed_lcv script_404 = mpld3.fig_to_html(fig_404, d3_url=D3_URL, mpld3_url=MPLD3_URL) script_404_HU = mpld3.fig_to_html(fig_404_HU, d3_url=D3_URL, mpld3_url=MPLD3_URL) # ############################## CTP486 - UNIFORMITY #################### fig_486 = Figure(figsize=(10.5, 5), tight_layout={"w_pad":0, "pad": 1.5}) ax486_1 = fig_486.add_subplot(1,2,1) ax486_2 = fig_486.add_subplot(1,2,2) if use_reference and ref_exists: ax486_1.imshow(mycbct_ref.ctp486.image.array, cmap=cmap, interpolation="none", aspect="equal", origin='upper') mycbct_ref.ctp486.plot_rois(ax486_1) # Add text inside ROI for reference to uniformity index: for ind, roi in enumerate(mycbct_ref.ctp486.rois.values()): ax486_1.text(roi.center.x, roi.center.y, str(ind), horizontalalignment='center', verticalalignment='center') else: ax486_1.text(0.5, 0.5 ,"Reference image not available", horizontalalignment='center', verticalalignment='center') ax486_2.imshow(mycbct.ctp486.image.array, cmap=cmap, interpolation="none", aspect="equal", origin='upper') mycbct.ctp486.plot_rois(ax486_2) # Add text inside ROI for reference to uniformity index: for ind, roi in enumerate(mycbct.ctp486.rois.values()): ax486_2.text(roi.center.x, roi.center.y, str(ind), horizontalalignment='center', verticalalignment='center') ax486_1.set_title('CTP486 reference image') ax486_1.autoscale(enable=False) ax486_2.set_title('CTP486 current image') ax486_2.autoscale(enable=False) script_486 = mpld3.fig_to_html(fig_486, d3_url=D3_URL, mpld3_url=MPLD3_URL) # Draw orthogonal profiles: fig_486_profile = Figure(figsize=(10.5, 5), tight_layout={"w_pad":0, "pad": 1.5}) ax486_profile_ref = fig_486_profile.add_subplot(1,2,1) ax486_profile = fig_486_profile.add_subplot(1,2,2) if use_reference and ref_exists: mycbct_ref.ctp486.plot_profiles(ax486_profile_ref) else: ax486_profile_ref.text(0.5, 0.5 ,"Reference image not available", horizontalalignment='center', verticalalignment='center') mycbct.ctp486.plot_profiles(ax486_profile) ax486_profile_ref.set_title('Reference uniformity profiles') ax486_profile.set_title('Current uniformity profiles') script_486_profile = mpld3.fig_to_html(fig_486_profile, d3_url=D3_URL, mpld3_url=MPLD3_URL) # Get mean pixel values and uniformity index: # take into account slope and intercept HU = slope * px + intercept if use_reference and ref_exists: hvalues_ref = [roi.pixel_value for roi in mycbct_ref.ctp486.rois.values()] uidx_ref = round(mycbct_ref.ctp486.uniformity_index, 2) else: hvalues_ref = [np.nan]*len(mycbct.ctp486.rois.values()) uidx_ref = np.nan hvalues = [roi.pixel_value for roi in mycbct.ctp486.rois.values()] passed_uniformity = mycbct.ctp486.overall_passed uidx = round(mycbct.ctp486.uniformity_index, 2) passed_uniformity_index = True if abs(uidx)<=uniformityidx_tolerance else False # ############################## CTP515 - LOW CONTRAST #################### if phantom != "Catphan 503": show_ctp515 = True fig_515 = Figure(figsize=(10.5, 5), tight_layout={"w_pad":0, "pad": 1.5}) ax515_1 = fig_515.add_subplot(1,2,1) ax515_2 = fig_515.add_subplot(1,2,2) if use_reference and ref_exists: ax515_1.imshow(mycbct_ref.ctp515.image.array, cmap=cmap, interpolation="none", aspect="equal", origin='upper') mycbct_ref.ctp515.plot_rois(ax515_1) else: ax515_1.text(0.5, 0.5 ,"Reference image not available", horizontalalignment='center', verticalalignment='center') ax515_2.imshow(mycbct.ctp515.image.array, cmap=cmap, interpolation="none", aspect="equal", origin='upper') mycbct.ctp515.plot_rois(ax515_2) ax515_1.set_title('CTP515 reference image') ax515_1.autoscale(enable=False) ax515_2.set_title('CTP515 current image') ax515_2.autoscale(enable=False) script_515 = mpld3.fig_to_html(fig_515, d3_url=D3_URL, mpld3_url=MPLD3_URL) fig_515_contrast = Figure(figsize=(10, 5), tight_layout={"w_pad":1, "pad": 1}) ax515_contrast = fig_515_contrast.add_subplot(1,2,1) ax515_cnr = fig_515_contrast.add_subplot(1,2,2) cnrs_names = [] contrasts_515 = [] cnrs515 = [] for key, value in mycbct.ctp515.rois.items(): cnrs_names.append(key) contrasts_515.append(value.contrast_constant) cnrs515.append(round(value.cnr_constant, 2)) sizes_515 = np.array(cnrs_names, dtype=int) ax515_contrast.plot(sizes_515, contrasts_515, marker='o', color="blue", markersize=8, markerfacecolor="None", linestyle="-") ax515_cnr.plot(sizes_515, cnrs515, marker='o', color="blue", markersize=8, markerfacecolor="None", linestyle="-") if use_reference and ref_exists: contrasts_515_ref = [] cnrs515_ref = [] cnrs_names_ref = [] for key, value in mycbct_ref.ctp515.rois.items(): cnrs_names_ref.append(key) contrasts_515_ref.append(value.contrast_constant) cnrs515_ref.append(round(value.cnr_constant, 2)) sizes_515_ref = np.array(cnrs_names_ref, dtype=int) ax515_contrast.plot(sizes_515_ref, contrasts_515_ref, marker='o', color="blue", markersize=8, markerfacecolor="None", linestyle="--") ax515_cnr.plot(sizes_515_ref, cnrs515_ref, marker='o', color="blue", markersize=8, markerfacecolor="None", linestyle="--") ctp515_visible_ref = mycbct_ref.ctp515.rois_visible else: ctp515_visible_ref = np.nan cnrs515_ref = [np.nan]*len(mycbct.ctp515.rois.values()) ax515_contrast.margins(0.05) ax515_contrast.grid(True) ax515_contrast.set_xlabel('ROI size (mm)') ax515_contrast.set_ylabel("Contrast * Diameter") ax515_cnr.margins(0.05) ax515_cnr.grid(True) ax515_cnr.set_xlabel('ROI size (mm)') ax515_cnr.set_ylabel("CNR * Diameter") script_515_contrast = mpld3.fig_to_html(fig_515_contrast, d3_url=D3_URL, mpld3_url=MPLD3_URL) ctp515_passed = mycbct.ctp515.overall_passed #ctp515_passed = None ctp515_visible = mycbct.ctp515.rois_visible else: show_ctp515 = False script_515_contrast = None script_515 = None ctp515_visible_ref = np.nan ctp515_passed = None ctp515_visible = np.nan cnrs515_ref = None cnrs515 = None cnrs_names = None general_functions.delete_files_in_subfolders([folder_path]) # Delete temporary images variables = { "script_ctp528": script_ctp528, "script_ctp528mtf": script_ctp528mtf, "mtf30_ref": round(mtf30_ref, 2), "mtf30": round(mtf30, 2), "mtf50_ref": round(mtf50_ref, 2), "mtf50": round(mtf50, 2), "mtf80_ref": round(mtf80_ref, 2), "mtf80": round(mtf80, 2), "mtf_passing": mtf_passing, "script_404": script_404, "script_404_HU": script_404_HU, "HU_values_ref": HU_values_ref, "HU_std_ref": HU_std_ref, "HU_values": HU_values, "HU_std": HU_std, "HU_nominal": HU_nominal, "HU_names": HU_names, "HU_diff_ref": HU_diff_ref, "HU_diff": HU_diff, "passed_HU": passed_HU, "passed_thickness": passed_thickness, "passed_geometry": passed_geometry, "passed_lcv": passed_lcv, "passed_404": passed_404, "lcv_ref": lcv_ref, "lcv": round(lcv, 2), "slice_thickness": slice_thickness, "slice_thickness_ref": slice_thickness_ref, "dicom_slice_thickness": dicom_slice_thickness, "dicom_slice_thickness_ref": dicom_slice_thickness_ref, "lines_ref": lines_ref, "lines": lines, "lines_avg": lines_avg, "lines_avg_ref": lines_avg_ref, "phantom_roll": phantom_roll, "phantom_roll_ref": phantom_roll_ref, "origin_slice_ref": origin_slice_ref, "origin_slice": origin_slice, "ctp528_slice": ctp528_slice, "ctp486_slice": ctp486_slice, "ctp515_slice": ctp515_slice, "ctp528_slice_ref": ctp528_slice_ref, "ctp486_slice_ref": ctp486_slice_ref, "ctp515_slice_ref": ctp515_slice_ref, "phantom_center_ref": phantom_center_ref, "phantom_center": phantom_center, "mm_per_pixel": mm_per_pixel, "mm_per_pixel_ref": mm_per_pixel_ref, "cnrs404_ref" : cnrs404_ref, "cnrs404": cnrs404, "script_486": script_486, "script_486_profile": script_486_profile, "hvalues_ref": hvalues_ref, "hvalues": hvalues, "passed_uniformity": passed_uniformity, "passed_uniformity_index": passed_uniformity_index, "uidx": uidx, "uidx_ref": uidx_ref, "script_515": script_515, "script_515_contrast": script_515_contrast, "show_ctp515": show_ctp515, "ctp515_passed": ctp515_passed, "ctp515_visible": ctp515_visible, "ctp515_visible_ref": ctp515_visible_ref, "cnrs515_ref": cnrs515_ref, "cnrs515": cnrs515, "cnrs_names": cnrs_names, "save_results": save_results, "acquisition_datetime": acquisition_datetime, "pdf_report_enable": pdf_report_enable } # Generate pylinac report: if pdf_report_enable == "True": pdf_file = tempfile.NamedTemporaryFile(delete=False, prefix="Catphan", suffix=".pdf", dir=config.PDF_REPORT_FOLDER) mycbct.publish_pdf(pdf_file) variables["pdf_report_filename"] = os.path.basename(pdf_file.name) except Exception as e: general_functions.delete_files_in_subfolders([folder_path]) # Delete temporary images return template("error_template", {"error_message": "Cannot analyze image. "+str(e) }) else: return template("catphan_results", variables)
def edit_settings_flatsym(): return template("edit_settings_flatsym")
def flatsym_helper_catch_error(args): try: return flatsym_helper(args) except Exception as e: return template("error_template", {"error_message": str(e)})
def edit_settings_vmat(): return template("edit_settings_vmat")
def edit_users(): return template("edit_users")
def edit_machine_mapping(): return template("edit_machine_mapping")
def fieldrot_helperf(args): test_type = args["test_type"] direction = args["direction"] direction2 = args["direction2"] number_samples = args["number_samples"] margin = args["margin"] clipbox = args["clipbox"] invert = args["invert"] w1 = args["w1"] w2 = args["w2"] colormap = args["colormap"] med_filter = args["med_filter"] general_functions.set_configuration(args["config"]) imgdescription = args["imgdescription"] station = args["station"] displayname = args["displayname"] acquisition_datetime = args["acquisition_datetime"] high_contrast = args["high_contrast"] # 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_fieldrotation()) tolerances = general_functions.get_tolerance_user_machine_fieldrotation( user_machine) # If user_machne has specific tolerance if not tolerances: tt = general_functions.get_settings_fieldrotation() else: tt = tolerances[0] (tolerance_collabs, tolerance_collrel, tolerance_couchrel) = tt tolerance_collabs = float(tolerance_collabs) tolerance_collrel = float(tolerance_collrel) tolerance_couchrel = float(tolerance_couchrel) save_results = { "user_machine": user_machine, "user_energy": user_energy, "machines_and_energies": machines_and_energies, "displayname": displayname, "nominal_angle": np.linspace(360, -360, 49).tolist() } try: temp_folder1, file_path1 = RestToolbox.GetSingleDcm( config.ORTHANC_URL, w1) temp_folder2, file_path2 = RestToolbox.GetSingleDcm( config.ORTHANC_URL, w2) except: return template("error_template", {"error_message": "Cannot read images."}) # Load first image try: img1 = pylinac_image.DicomImage(file_path1) # Here we force pixels to background outside of box: if clipbox != 0: try: img1.check_inversion_by_histogram(percentiles=[ 4, 50, 96 ]) # Check inversion otherwise this might not work general_functions.clip_around_image(img1, clipbox) except Exception as e: return template( "error_template", {"error_message": "Unable to apply clipbox. " + str(e)}) else: img1.remove_edges(pixels=2) if invert: img1.invert() else: img1.check_inversion() img1.flipud() except: return template("error_template", {"error_message": "Cannot read image."}) try: img2 = pylinac_image.DicomImage(file_path2) if clipbox != 0: try: img2.check_inversion_by_histogram(percentiles=[ 4, 50, 96 ]) # Check inversion otherwise this might not work general_functions.clip_around_image(img2, clipbox) except Exception as e: return template( "error_template", {"error_message": "Unable to apply clipbox. " + str(e)}) else: img2.remove_edges(pixels=2) if invert: img2.invert() else: img2.check_inversion() img2.flipud() except: return template("error_template", {"error_message": "Cannot read image."}) # Apply some filtering if med_filter > 0: img1.filter(med_filter) img2.filter(med_filter) # Get radiation field box: try: center_cax1, rad_field_bounding_box1, field_corners1 = field_rotation._find_field_centroid( img1) center_cax2, rad_field_bounding_box2, field_corners2 = field_rotation._find_field_centroid( img2) except Exception as e: return template("error_template", {"error_message": str(e)}) field_corners1 = field_corners1.astype(int) field_corners2 = field_corners2.astype(int) # Set colormap cmap = matplotlib.cm.get_cmap(colormap) if test_type == "Collimator absolute": # Get BBs try: if high_contrast: bbs1 = field_rotation._find_bb2(img1, rad_field_bounding_box1) bbs2 = field_rotation._find_bb2(img2, rad_field_bounding_box2) else: bbs1 = field_rotation._find_bb(img1, rad_field_bounding_box1) bbs2 = field_rotation._find_bb(img2, rad_field_bounding_box2) except Exception as e: return template("error_template", {"error_message": str(e)}) bb_coord1_1, bw_bb_im1_1 = bbs1[0] bb_coord1_2, bw_bb_im1_2 = bbs1[1] bb_coord2_1, bw_bb_im2_1 = bbs2[0] bb_coord2_2, bw_bb_im2_2 = bbs2[1] center1_1 = (bb_coord1_1[0], bb_coord1_1[1]) center1_2 = (bb_coord1_2[0], bb_coord1_2[1]) center2_1 = (bb_coord2_1[0], bb_coord2_1[1]) center2_2 = (bb_coord2_2[0], bb_coord2_2[1]) # Line between BBs: bb_angle1 = np.arctan(np.inf if bb_coord1_1[0] - bb_coord1_2[0] == 0 else (bb_coord1_1[1] - bb_coord1_2[1]) / (bb_coord1_1[0] - bb_coord1_2[0])) * 180 / np.pi bb_angle2 = np.arctan(np.inf if bb_coord2_1[0] - bb_coord2_2[0] == 0 else (bb_coord2_1[1] - bb_coord2_2[1]) / (bb_coord2_1[0] - bb_coord2_2[0])) * 180 / np.pi img1_filled = np.copy(img1.array) img2_filled = np.copy(img2.array) # Fill BBs area with neighbouring values field_rotation.fill_BB_hole(bb_coord1_1, bw_bb_im1_1, img1_filled) field_rotation.fill_BB_hole(bb_coord1_2, bw_bb_im1_2, img1_filled) field_rotation.fill_BB_hole(bb_coord2_1, bw_bb_im2_1, img2_filled) field_rotation.fill_BB_hole(bb_coord2_2, bw_bb_im2_2, img2_filled) # Get penumbra points try: samples_left1, samples_right1, p_left1, p_right1 = field_rotation.find_penumbra_points( direction, number_samples, field_corners1, margin, img1_filled) samples_left2, samples_right2, p_left2, p_right2 = field_rotation.find_penumbra_points( direction2, number_samples, field_corners2, margin, img2_filled) except Exception as e: return template("error_template", {"error_message": str(e)}) # Calculate field edge slopes pmin = 0 pmax = np.max( img1.shape) # Maksimum point for drawing regression lines if direction == "X": left_slope1, left_P1, left_err1 = field_rotation.calculate_regression( p_left1, samples_left1, pmin, pmax) right_slope1, right_P1, right_err1 = field_rotation.calculate_regression( p_right1, samples_right1, pmin, pmax) else: left_slope1, left_P1, left_err1 = field_rotation.calculate_regression( samples_left1, p_left1, pmin, pmax) right_slope1, right_P1, right_err1 = field_rotation.calculate_regression( samples_right1, p_right1, pmin, pmax) if direction2 == "X": left_slope2, left_P2, left_err2 = field_rotation.calculate_regression( p_left2, samples_left2, pmin, pmax) right_slope2, right_P2, right_err2 = field_rotation.calculate_regression( p_right2, samples_right2, pmin, pmax) else: left_slope2, left_P2, left_err2 = field_rotation.calculate_regression( samples_left2, p_left2, pmin, pmax) right_slope2, right_P2, right_err2 = field_rotation.calculate_regression( samples_right2, p_right2, pmin, pmax) left_edge_angle1 = np.arctan(left_slope1) * 180 / np.pi left_edge_angle2 = np.arctan(left_slope2) * 180 / np.pi right_edge_angle1 = np.arctan(right_slope1) * 180 / np.pi right_edge_angle2 = np.arctan(right_slope2) * 180 / np.pi # First plot: field and penumbra points fig1 = Figure(figsize=(10.5, 5.5), tight_layout={"w_pad": 3, "pad": 3}) ax1 = fig1.add_subplot(1, 2, 1) ax2 = fig1.add_subplot(1, 2, 2) # Plot error bars and goodness of fit fig2 = Figure(figsize=(10, 4), tight_layout={"w_pad": 0, "pad": 1}) ax3 = fig2.add_subplot(1, 2, 1) ax4 = fig2.add_subplot(1, 2, 2) # Plot angled lines fig3 = Figure(figsize=(10, 4), tight_layout={"w_pad": 0, "pad": 1}) ax5 = fig3.add_subplot(1, 2, 1) ax6 = fig3.add_subplot(1, 2, 2) ax1.imshow(img1.array, cmap=cmap, interpolation="none", aspect="equal", origin='lower') ax1.set_title('Image 1') ax1.axis('off') ax2.imshow(img2.array, cmap=cmap, interpolation="none", aspect="equal", origin='lower') ax2.set_title('Image 2') ax2.axis('off') #Plot field corners ax1.plot(field_corners1[:, 1], field_corners1[:, 0], "mo", markersize=5, markeredgewidth=0) ax2.plot(field_corners2[:, 1], field_corners2[:, 0], "mo", markersize=5, markeredgewidth=0) # Plot penumbra points if direction == "X": ax1.plot(p_left1, samples_left1, "bx", markersize=5, markeredgewidth=2) ax1.plot(p_right1, samples_right1, "yx", markersize=5, markeredgewidth=2) else: ax1.plot(samples_left1, p_left1, "bx", markersize=5, markeredgewidth=2) ax1.plot(samples_right1, p_right1, "yx", markersize=5, markeredgewidth=2) ax1.plot(left_P1[0], left_P1[1], "b--") ax1.plot(right_P1[0], right_P1[1], "y--") if direction2 == "X": ax2.plot(p_left2, samples_left2, "bx", markersize=5, markeredgewidth=2) ax2.plot(p_right2, samples_right2, "yx", markersize=5, markeredgewidth=2) else: ax2.plot(samples_left2, p_left2, "bx", markersize=5, markeredgewidth=2) ax2.plot(samples_right2, p_right2, "yx", markersize=5, markeredgewidth=2) ax2.plot(left_P2[0], left_P2[1], "b--") ax2.plot(right_P2[0], right_P2[1], "y--") # Plot errors: ax3.plot(samples_left1, left_err1, "bx", markeredgewidth=2) ax3.plot(samples_right1, right_err1, "yx", markeredgewidth=2) ax4.plot(samples_left2, left_err2, "bx", markeredgewidth=2) ax4.plot(samples_right2, right_err2, "yx", markeredgewidth=2) limits_max = np.amax([ np.amax(left_err1), np.amax(right_err1), np.amax(left_err2), np.amax(right_err2) ]) * 1.05 limits_min = np.amin([ np.amin(left_err1), np.amin(right_err1), np.amin(left_err2), np.amin(right_err2) ]) * 0.95 limits = np.amax([abs(limits_max), abs(limits_min)]) limits = limits if limits > 1 else 1 ax3.set_ylim([-limits, limits]) ax4.set_ylim([-limits, limits]) ax3.set_ylabel("Deviation from fit [px]") ax4.set_ylabel("Deviation from fit [px]") ax3.set_xlabel("Field edge [px]") ax4.set_xlabel("Field edge [px]") ax3.set_title('Image 1 - Regression error') ax4.set_title('Image 2 - Regression error') # Plot angled lines: # If angles are negative, convert to [pi, 2pi] if abs(bb_angle1) > 80 and abs(bb_angle1) <= 90: B1 = left_edge_angle1 if left_edge_angle1 >= 0 else 180 + left_edge_angle1 Y1 = right_edge_angle1 if right_edge_angle1 >= 0 else 180 + right_edge_angle1 BB1 = bb_angle1 if bb_angle1 >= 0 else 180 + bb_angle1 ref_angle_plot = PI / 2 # Reference angle for drawing (either 0 or 90) else: B1 = left_edge_angle1 Y1 = right_edge_angle1 BB1 = bb_angle1 ref_angle_plot = 0 if abs(bb_angle2) > 80 and abs(bb_angle2) <= 90: B2 = left_edge_angle2 if left_edge_angle2 >= 0 else 180 + left_edge_angle2 Y2 = right_edge_angle2 if right_edge_angle2 >= 0 else 180 + right_edge_angle2 BB2 = bb_angle2 if bb_angle2 >= 0 else 180 + bb_angle2 else: B2 = left_edge_angle2 Y2 = right_edge_angle2 BB2 = bb_angle2 a = 2 x_bb1 = [-a * np.cos(BB1 * PI / 180), a * np.cos(BB1 * PI / 180)] y_bb1 = [-a * np.sin(BB1 * PI / 180), a * np.sin(BB1 * PI / 180)] x_b1 = [-a * np.cos((B1) * PI / 180), a * np.cos((B1) * PI / 180)] y_b1 = [-a * np.sin((B1) * PI / 180), a * np.sin((B1) * PI / 180)] x_b2 = [ -a * np.cos((BB1 - (B2 - BB2)) * PI / 180), a * np.cos( (BB1 - (B2 - BB2)) * PI / 180) ] y_b2 = [ -a * np.sin((BB1 - (B2 - BB2)) * PI / 180), a * np.sin( (BB1 - (B2 - BB2)) * PI / 180) ] x_y1 = [-a * np.cos((Y1) * PI / 180), a * np.cos((Y1) * PI / 180)] y_y1 = [-a * np.sin((Y1) * PI / 180), a * np.sin((Y1) * PI / 180)] x_y2 = [ -a * np.cos((BB1 - (Y2 - BB2)) * PI / 180), a * np.cos( (BB1 - (Y2 - BB2)) * PI / 180) ] y_y2 = [ -a * np.sin((BB1 - (Y2 - BB2)) * PI / 180), a * np.sin( (BB1 - (Y2 - BB2)) * PI / 180) ] ax5.plot(x_bb1, y_bb1, "g-", label="BB") ax5.plot(x_b1, y_b1, "b-", label="Gantry 0") ax5.plot(x_b2, y_b2, "b--", label="Gantry 180") ax6.plot(x_bb1, y_bb1, "g-", label="BB") ax6.plot(x_y1, y_y1, "y-", label="Gantry 0") ax6.plot(x_y2, y_y2, "y--", label="Gantry 180") if ref_angle_plot == PI / 2: max_xb = np.amax([np.abs(x_b1), np.abs(x_b2)]) max_xy = np.amax([np.abs(x_y1), np.abs(x_y2)]) ax5.set_xlim([-2 * max_xb, 2 * max_xb]) ax5.set_ylim([-1, 1]) ax6.set_xlim([-2 * max_xy, 2 * max_xy]) ax6.set_ylim([-1, 1]) else: max_y = np.amax([np.abs(y_b1), np.abs(y_b2)]) max_yy = np.amax([np.abs(y_y1), np.abs(y_y2)]) ax5.set_ylim([-2 * max_y, 2 * max_y]) ax5.set_xlim([-1, 1]) ax6.set_ylim([-2 * max_yy, 2 * max_yy]) ax6.set_xlim([-1, 1]) ax5.legend(loc='upper right', fontsize=10, edgecolor="none") ax5.set_title("Blue edge") ax5.set_xlabel("LAT [px]") ax5.set_ylabel("LONG [px]") ax6.legend(loc='upper right', fontsize=10, edgecolor="none") ax6.set_title("Yellow edge") ax6.set_xlabel("LAT [px]") ax6.set_ylabel("LONG [px]") # Plot BB line and crosses ax1.plot([bb_coord1_1[0], bb_coord1_2[0]], [bb_coord1_1[1], bb_coord1_2[1]], "g-") ax2.plot([bb_coord2_1[0], bb_coord2_2[0]], [bb_coord2_1[1], bb_coord2_2[1]], "g-") ax1.plot(center1_1[0], center1_1[1], 'r+', markersize=10, markeredgewidth=2) ax1.plot(center1_2[0], center1_2[1], 'r+', markersize=10, markeredgewidth=2) ax2.plot(center2_1[0], center2_1[1], 'r+', markersize=10, markeredgewidth=2) ax2.plot(center2_2[0], center2_2[1], 'r+', markersize=10, markeredgewidth=2) ax1.set_xlim([0, img1.shape[1]]) ax1.set_ylim([0, img1.shape[0]]) ax2.set_xlim([0, img2.shape[1]]) ax2.set_ylim([0, img2.shape[0]]) script1 = mpld3.fig_to_html(fig1, d3_url=D3_URL, mpld3_url=MPLD3_URL) script2 = mpld3.fig_to_html(fig2, d3_url=D3_URL, mpld3_url=MPLD3_URL) script3 = mpld3.fig_to_html(fig3, d3_url=D3_URL, mpld3_url=MPLD3_URL) variables = { "script1": script1, "script2": script2, "script3": script3, "left_edge_angle1": left_edge_angle1, "left_edge_angle2": left_edge_angle2, "right_edge_angle1": right_edge_angle1, "right_edge_angle2": right_edge_angle2, "bb_angle1": bb_angle1, "bb_angle2": bb_angle2, "test_type": test_type, "tolerance": tolerance_collabs } elif test_type == "Collimator relative": # Get penumbra points try: samples_left1, samples_right1, p_left1, p_right1 = field_rotation.find_penumbra_points( direction, number_samples, field_corners1, margin, img1.array) samples_left2, samples_right2, p_left2, p_right2 = field_rotation.find_penumbra_points( direction2, number_samples, field_corners2, margin, img2.array) except Exception as e: return template("error_template", {"error_message": str(e)}) # Calculate field edge slopes pmin = 0 pmax = np.max( img1.shape) # Maksimum point for drawing regression lines if direction == "X": left_slope1, left_P1, left_err1 = field_rotation.calculate_regression( p_left1, samples_left1, pmin, pmax) right_slope1, right_P1, right_err1 = field_rotation.calculate_regression( p_right1, samples_right1, pmin, pmax) else: left_slope1, left_P1, left_err1 = field_rotation.calculate_regression( samples_left1, p_left1, pmin, pmax) right_slope1, right_P1, right_err1 = field_rotation.calculate_regression( samples_right1, p_right1, pmin, pmax) if direction2 == "X": left_slope2, left_P2, left_err2 = field_rotation.calculate_regression( p_left2, samples_left2, pmin, pmax) right_slope2, right_P2, right_err2 = field_rotation.calculate_regression( p_right2, samples_right2, pmin, pmax) else: left_slope2, left_P2, left_err2 = field_rotation.calculate_regression( samples_left2, p_left2, pmin, pmax) right_slope2, right_P2, right_err2 = field_rotation.calculate_regression( samples_right2, p_right2, pmin, pmax) left_edge_angle1 = np.arctan(left_slope1) * 180 / np.pi left_edge_angle2 = np.arctan(left_slope2) * 180 / np.pi right_edge_angle1 = np.arctan(right_slope1) * 180 / np.pi right_edge_angle2 = np.arctan(right_slope2) * 180 / np.pi # First plot: field and penumbra points fig1 = Figure(figsize=(10.5, 5.5), tight_layout={"w_pad": 3, "pad": 3}) ax1 = fig1.add_subplot(1, 2, 1) ax2 = fig1.add_subplot(1, 2, 2) # Plot error bars and goodness of fit fig2 = Figure(figsize=(10, 4), tight_layout={"w_pad": 0, "pad": 1}) ax3 = fig2.add_subplot(1, 2, 1) ax4 = fig2.add_subplot(1, 2, 2) ax1.imshow(img1.array, cmap=cmap, interpolation="none", aspect="equal", origin='lower') ax1.set_title('Image 1') ax1.axis('off') ax2.imshow(img2.array, cmap=cmap, interpolation="none", aspect="equal", origin='lower') ax2.set_title('Image 2') ax2.axis('off') #Plot field corners ax1.plot(field_corners1[:, 1], field_corners1[:, 0], "mo", markersize=5, markeredgewidth=0) ax2.plot(field_corners2[:, 1], field_corners2[:, 0], "mo", markersize=5, markeredgewidth=0) # Plot penumbra points if direction == "X": ax1.plot(p_left1, samples_left1, "bx", markersize=5, markeredgewidth=2) ax1.plot(p_right1, samples_right1, "yx", markersize=5, markeredgewidth=2) else: ax1.plot(samples_left1, p_left1, "bx", markersize=5, markeredgewidth=2) ax1.plot(samples_right1, p_right1, "yx", markersize=5, markeredgewidth=2) ax1.plot(left_P1[0], left_P1[1], "b--") ax1.plot(right_P1[0], right_P1[1], "y--") if direction2 == "X": ax2.plot(p_left2, samples_left2, "bx", markersize=5, markeredgewidth=2) ax2.plot(p_right2, samples_right2, "yx", markersize=5, markeredgewidth=2) else: ax2.plot(samples_left2, p_left2, "bx", markersize=5, markeredgewidth=2) ax2.plot(samples_right2, p_right2, "yx", markersize=5, markeredgewidth=2) ax2.plot(left_P2[0], left_P2[1], "b--") ax2.plot(right_P2[0], right_P2[1], "y--") ax1.set_xlim([0, img1.shape[1]]) ax1.set_ylim([0, img1.shape[0]]) ax2.set_xlim([0, img2.shape[1]]) ax2.set_ylim([0, img2.shape[0]]) # Plot errors: ax3.plot(samples_left1, left_err1, "bx", markeredgewidth=2) ax3.plot(samples_right1, right_err1, "yx", markeredgewidth=2) ax4.plot(samples_left2, left_err2, "bx", markeredgewidth=2) ax4.plot(samples_right2, right_err2, "yx", markeredgewidth=2) limits_max = np.amax([ np.amax(left_err1), np.amax(right_err1), np.amax(left_err2), np.amax(right_err2) ]) * 1.05 limits_min = np.amin([ np.amin(left_err1), np.amin(right_err1), np.amin(left_err2), np.amin(right_err2) ]) * 0.95 limits = np.amax([abs(limits_max), abs(limits_min)]) limits = limits if limits > 1 else 1 ax3.set_ylim([-limits, limits]) ax4.set_ylim([-limits, limits]) ax3.set_ylabel("Deviation from fit [px]") ax4.set_ylabel("Deviation from fit [px]") ax3.set_xlabel("Field edge [px]") ax4.set_xlabel("Field edge [px]") ax3.set_title('Image 1 - Regression error') ax4.set_title('Image 2 - Regression error') script1 = mpld3.fig_to_html(fig1, d3_url=D3_URL, mpld3_url=MPLD3_URL) script2 = mpld3.fig_to_html(fig2, d3_url=D3_URL, mpld3_url=MPLD3_URL) variables = { "script1": script1, "script2": script2, "script3": "", "left_edge_angle1": left_edge_angle1, "left_edge_angle2": left_edge_angle2, "right_edge_angle1": right_edge_angle1, "right_edge_angle2": right_edge_angle2, "test_type": test_type, "tolerance": tolerance_collrel } else: # Couch rotation # Get BBs try: if high_contrast: bbs1 = field_rotation._find_bb2(img1, rad_field_bounding_box1) bbs2 = field_rotation._find_bb2(img2, rad_field_bounding_box2) else: bbs1 = field_rotation._find_bb(img1, rad_field_bounding_box1) bbs2 = field_rotation._find_bb(img2, rad_field_bounding_box2) except Exception as e: return template("error_template", {"error_message": str(e)}) bb_coord1_1, bw_bb_im1_1 = bbs1[0] bb_coord1_2, bw_bb_im1_2 = bbs1[1] bb_coord2_1, bw_bb_im2_1 = bbs2[0] bb_coord2_2, bw_bb_im2_2 = bbs2[1] center1_1 = [bb_coord1_1[0], bb_coord1_1[1]] center1_2 = [bb_coord1_2[0], bb_coord1_2[1]] center2_1 = [bb_coord2_1[0], bb_coord2_1[1]] center2_2 = [bb_coord2_2[0], bb_coord2_2[1]] bb_line_center1 = [ np.average([center1_1[0], center1_2[0]]), np.average([center1_1[1], center1_2[1]]) ] bb_line_center2 = [ np.average([center2_1[0], center2_2[0]]), np.average([center2_1[1], center2_2[1]]) ] # Line between BBs: bb_angle1 = np.arctan(np.inf if bb_coord1_1[0] - bb_coord1_2[0] == 0 else (bb_coord1_1[1] - bb_coord1_2[1]) / (bb_coord1_1[0] - bb_coord1_2[0])) * 180 / np.pi bb_angle2 = np.arctan(np.inf if bb_coord2_1[0] - bb_coord2_2[0] == 0 else (bb_coord2_1[1] - bb_coord2_2[1]) / (bb_coord2_1[0] - bb_coord2_2[0])) * 180 / np.pi fig1 = Figure(figsize=(10.5, 5.5), tight_layout={"w_pad": 3, "pad": 3}) ax1 = fig1.add_subplot(1, 2, 1) ax2 = fig1.add_subplot(1, 2, 2) ax1.imshow(img1.array, cmap=cmap, interpolation="none", aspect="equal", origin='lower') ax1.set_title('Image 1') ax1.axis('off') ax2.imshow(img2.array, cmap=cmap, interpolation="none", aspect="equal", origin='lower') ax2.set_title('Image 2') ax2.axis('off') # Plot BB line and crosses ax1.plot([bb_coord1_1[0], bb_coord1_2[0]], [bb_coord1_1[1], bb_coord1_2[1]], "g-") ax2.plot([bb_coord2_1[0], bb_coord2_2[0]], [bb_coord2_1[1], bb_coord2_2[1]], "g-") ax1.plot(center1_1[0], center1_1[1], 'r+', markersize=10, markeredgewidth=2) ax1.plot(center1_2[0], center1_2[1], 'r+', markersize=10, markeredgewidth=2) ax2.plot(center2_1[0], center2_1[1], 'r+', markersize=10, markeredgewidth=2) ax2.plot(center2_2[0], center2_2[1], 'r+', markersize=10, markeredgewidth=2) ax1.set_xlim([0, img1.shape[1]]) ax1.set_ylim([0, img1.shape[0]]) ax2.set_xlim([0, img2.shape[1]]) ax2.set_ylim([0, img2.shape[0]]) script1 = mpld3.fig_to_html(fig1, d3_url=D3_URL, mpld3_url=MPLD3_URL) variables = { "script1": script1, "script2": "", "script3": "", "bb_angle1": bb_angle1, "bb_angle2": bb_angle2, "bb_line_center1": bb_line_center1, "bb_line_center2": bb_line_center2, "test_type": test_type, "tolerance": tolerance_couchrel } variables["acquisition_datetime"] = acquisition_datetime variables["save_results"] = save_results general_functions.delete_files_in_subfolders([temp_folder1, temp_folder2 ]) # Delete image return template("fieldrot_results", variables)
def edit_settings_planarimaging(): variables = {"phantoms": config.PLANARIMAGING_PHANTOMS} return template("edit_settings_planarimaging", variables)