def run_test( field_centre, field_side_lengths, field_penumbra, field_rotation, bb_centre, bb_diameter, bb_max_attenuation, ): x, y, img = create_test_image( field_centre, field_side_lengths, field_penumbra, field_rotation, bb_centre, bb_diameter, bb_max_attenuation, ) ( determined_bb_centre, determined_field_centre, determined_field_rotation, ) = pymedphys.wlutz.find_field_and_bb( x, y, img, field_side_lengths, bb_diameter, penumbra=field_penumbra, pylinac_tol=None, ) try: assert np.allclose(bb_centre, determined_bb_centre, atol=0.001) assert np.allclose(field_centre, determined_field_centre, atol=0.001) assert np.allclose(field_rotation, determined_field_rotation, atol=0.01) except: reporting.image_analysis_figure( x, y, img, determined_bb_centre, determined_field_centre, determined_field_rotation, bb_diameter, field_side_lengths, field_penumbra, ) raise
def optimise_rotation(field, centre, edge_lengths, penumbra): to_minimise = create_rotation_only_minimiser(field, centre, edge_lengths, penumbra) result = scipy.optimize.basinhopping( to_minimise, INITIAL_ROTATION, T=1, niter=BASINHOPPING_NITER, niter_success=5, stepsize=90, minimizer_kwargs={"method": "L-BFGS-B"}, ) predicted_rotation = result.x[0] if np.allclose(*edge_lengths, rtol=0.001, atol=0.001): modulo_rotation = predicted_rotation % 90 if modulo_rotation >= 45: modulo_rotation = modulo_rotation - 90 return modulo_rotation modulo_rotation = predicted_rotation % 180 if modulo_rotation >= 90: modulo_rotation = modulo_rotation - 180 return modulo_rotation
def check_centre_close(verification_centre, predicted_centre): if not np.allclose( verification_centre, predicted_centre, rtol=0.01, atol=0.01): raise ValueError( "Field centre not able to be reproducibly determined.\n" f" Verification Centre: {verification_centre}\n" f" Predicted Centre: {predicted_centre}\n")
def check_aspect_ratio(edge_lengths): if not np.allclose(*edge_lengths): if np.min(edge_lengths) > 0.95 * np.max(edge_lengths): raise ValueError( "For non-square rectangular fields, " "to accurately determine the rotation, " "need to have the small edge be less than 95% of the long edge." )
def advanced_debugging(): config = get_config() st.sidebar.markdown("# Advanced Debugging") if st.sidebar.button("Compare Baseline to Output Directory"): """ ## Comparing Results to Baseline """ baseline_directory = pathlib.Path( config["debug"]["baseline_directory"]).resolve() png_baseline_directory = baseline_directory.joinpath("png") baseline_png_paths = [ path for path in (png_baseline_directory.rglob("*")) if path.is_file() ] relative_png_paths = [ path.relative_to(png_baseline_directory) for path in baseline_png_paths ] output_dir = pathlib.Path(config["output"]["png_directory"]).resolve() evaluation_png_paths = [ output_dir.joinpath(path) for path in relative_png_paths ] for baseline, evaluation in zip(baseline_png_paths, evaluation_png_paths): f"### {baseline.parent.name}/{baseline.name}" f"`{baseline}`\n\n**vs**\n\n`{evaluation}`" baseline_image = imageio.imread(baseline) try: evaluation_image = imageio.imread(evaluation) except FileNotFoundError as e: """ #### File was not found """ st.write(e) f""" For debugging purposes, here are all the files that were found within {str(output_dir)} """ [str(path) for path in output_dir.rglob("*") if path.is_file()] return agree = np.allclose(baseline_image, evaluation_image) f"Images Agree: `{agree}`"
def check_rotation_close(edge_lengths, verification_rotation, predicted_rotation): if np.allclose(*edge_lengths): diff = (verification_rotation - predicted_rotation) % 90 if not (diff < 0.3 or diff > 89.7): raise ValueError( _rotation_error_string(verification_rotation, predicted_rotation, diff)) else: diff = (verification_rotation - predicted_rotation) % 180 if not (diff < 0.3 or diff > 179.7): raise ValueError( _rotation_error_string(verification_rotation, predicted_rotation, diff))
def read_prs(file_name): """ Read native Profiler data file and return dose profiles. Parameters ---------- file_name : string | file name of Profiler file including path Returns ------- Profiler : named tuple | Profiler.cax = float dose at central axis | Profiler.x = list of (x, dose) tuples | Profiler.y = list of (y, dose) tuples """ Profiler = namedtuple("Profiler", ["cax", "x", "y"]) with open(file_name) as profiler_file: for row in profiler_file.readlines(): contents = row if contents[:11] == "Calibration" and "File" not in contents: calibs = np.array(contents.split())[1:].astype(float) elif contents[:5] == "Data:": counts = np.array(contents.split()[5:145]).astype(float) elif contents[:15] == "Dose Per Count:": dose_per_count = float(contents.split()[-1]) assert (len(calibs)) == (len(counts)) == 140 assert dose_per_count > 0.0 dose = counts * dose_per_count * calibs y_vals = [-16.4 + 0.4 * i for i in range(83)] x_vals = [-11.2 + 0.4 * i for i in range(57)] x_prof = list(zip(y_vals, dose[:57])) y_prof = list(zip(x_vals, dose[57:])) assert np.allclose(y_prof[41][1], x_prof[28][1]) cax_dose = y_prof[41][1] return Profiler(cax_dose, x_prof, y_prof)