def batch_process(image_paths, edge_lengths, bb_diameter=8, penumbra=2, display_figure=True): bb_centres = [] field_centres = [] field_rotations = [] for image_path in image_paths: bb_centre, field_centre, field_rotation = iview_find_bb_and_field( image_path, edge_lengths, bb_diameter=bb_diameter, penumbra=penumbra, display_figure=display_figure, ) bb_centres.append(bb_centre) field_centres.append(field_centre) field_rotations.append(field_rotation) if display_figure: plt.show() data = np.concatenate( [bb_centres, field_centres, np.array(field_rotations)[:, None]], axis=1) return pd.DataFrame( data=data, columns=["BB x", "BB y", "Field x", "Field y", "Rotation"])
def calc_calibration_points(prescans, postscans, alignments=None, figures=False, pixel_trim=0): """Returns calibration points based on dictionaries of prescans and postscans. The key of the dictionaries of images is to represent the dose calibration point. If the key cannot be converted into a float that image will be ignored. """ keys = prescans.keys() assert keys == postscans.keys() calibration_points = {} if alignments is None: alignments = {key: None for key in keys} for key in keys: try: dose_value = float(key) except ValueError: warnings.warn( "{} does not appear to be a calibration image key. This will " "be skipped.") continue net_od, alignment = calc_net_od(prescans[key], postscans[key], alignment=alignments[key]) if pixel_trim != 0: trim_ref = (slice(pixel_trim, -pixel_trim), slice(pixel_trim, -pixel_trim)) net_od = net_od[trim_ref] if figures: plt.figure() plt.imshow(net_od) plt.show() calibration_points[dose_value] = np.median(net_od) alignments[key] = alignment return calibration_points, alignments
def plot_results( grid_xx, grid_yy, logfile_mu_density, mosaiq_mu_density, diff_colour_scale=0.1 ): min_val = np.min([logfile_mu_density, mosaiq_mu_density]) max_val = np.max([logfile_mu_density, mosaiq_mu_density]) plt.figure() plt.pcolormesh(grid_xx, grid_yy, logfile_mu_density, vmin=min_val, vmax=max_val) plt.colorbar() plt.title("Logfile MU density") plt.xlabel("MLC direction (mm)") plt.ylabel("Jaw direction (mm)") plt.gca().invert_yaxis() plt.figure() plt.pcolormesh(grid_xx, grid_yy, mosaiq_mu_density, vmin=min_val, vmax=max_val) plt.colorbar() plt.title("Mosaiq MU density") plt.xlabel("MLC direction (mm)") plt.ylabel("Jaw direction (mm)") plt.gca().invert_yaxis() scaled_diff = (logfile_mu_density - mosaiq_mu_density) / max_val plt.figure() plt.pcolormesh( grid_xx, grid_yy, scaled_diff, vmin=-diff_colour_scale / 2, vmax=diff_colour_scale / 2, ) plt.colorbar(label="Limited colour range = {}".format(diff_colour_scale / 2)) plt.title("(Logfile - Mosaiq MU density) / Maximum MU Density") plt.xlabel("MLC direction (mm)") plt.ylabel("Jaw direction (mm)") plt.gca().invert_yaxis() plt.show() plt.figure() plt.pcolormesh( grid_xx, grid_yy, scaled_diff, vmin=-diff_colour_scale, vmax=diff_colour_scale ) plt.colorbar(label="Limited colour range = {}".format(diff_colour_scale)) plt.title("(Logfile - Mosaiq MU density) / Maximum MU Density") plt.xlabel("MLC direction (mm)") plt.ylabel("Jaw direction (mm)") plt.gca().invert_yaxis() plt.show() absolute_range = np.max([-np.min(scaled_diff), np.max(scaled_diff)]) plt.figure() plt.pcolormesh( grid_xx, grid_yy, scaled_diff, vmin=-absolute_range, vmax=absolute_range ) plt.colorbar(label="No limited colour range") plt.title("(Logfile - Mosaiq MU density) / Maximum MU Density") plt.xlabel("MLC direction (mm)") plt.ylabel("Jaw direction (mm)") plt.gca().invert_yaxis() plt.show()
def optimise_bb_centre( field: imginterp.Field, bb_diameter, edge_lengths, penumbra, field_centre, field_rotation, pylinac_tol=0.2, debug=True, ): centralised_field = utilities.create_centralised_field( field, field_centre, field_rotation) to_minimise_edge_agreement = create_bb_to_minimise(centralised_field, bb_diameter) bb_bounds = define_bb_bounds(bb_diameter, edge_lengths, penumbra) bb_centre_in_centralised_field = bb_basinhopping( to_minimise_edge_agreement, bb_bounds) if check_if_at_bounds(bb_centre_in_centralised_field, bb_bounds): raise ValueError("BB found at bounds, likely incorrect") bb_centre = utilities.transform_point(bb_centre_in_centralised_field, field_centre, field_rotation) verification_repeat = bb_basinhopping(to_minimise_edge_agreement, bb_bounds) repeat_agreement = np.abs(verification_repeat - bb_centre_in_centralised_field) if np.any(repeat_agreement > BB_REPEAT_TOL): bb_repeated = utilities.transform_point(verification_repeat, field_centre, field_rotation) if debug: reporting.image_analysis_figure( field.x, field.y, field.img, bb_centre, field_centre, field_rotation, bb_diameter, edge_lengths, penumbra, ) plt.title("First iteration") reporting.image_analysis_figure( field.x, field.y, field.img, bb_repeated, field_centre, field_rotation, bb_diameter, edge_lengths, penumbra, ) plt.title("Second iteration") plt.show() raise ValueError("BB centre not able to be consistently determined\n" f" First iteration: {bb_centre}\n" f" Second iteration: {bb_repeated}") if not pylinac_tol is None: try: pylinac_result = pylinac.run_wlutz( field, edge_lengths, penumbra, field_centre, field_rotation, find_bb=True, pylinac_versions=("v2.2.6", ), ) except ValueError: raise ValueError( "While comparing result to PyLinac an error was raised") # warnings.simplefilter("always", UserWarning) # warnings.warn( # "This iteration has not been checked against pylinac. " # "When attempting to run pylinac instead an error was " # f"raised. Pylinac raised the following error:\n\n{e}\n" # ) # pylinac = {} try: pylinac_2_2_6_out_of_tol = np.any( np.abs( np.array(pylinac_result["v2.2.6"]["bb_centre"]) - bb_centre) > pylinac_tol) if pylinac_2_2_6_out_of_tol: raise pylinac.PylinacComparisonDeviation( "The determined bb centre deviates from pylinac more " "than the defined tolerance") except KeyError: pass return bb_centre
def plot(self): """Plot the profile.""" plt.plot(self.values) plt.show()