def gamma_filter_brute_force(axes_reference, dose_reference, axes_evaluation, dose_evaluation, distance_mm_threshold, dose_threshold, lower_dose_cutoff=0, **_): xx_ref, yy_ref, zz_ref = np.meshgrid(*axes_reference, indexing="ij") gamma_array = np.ones_like(dose_evaluation).astype(np.float) * np.nan mesh_index = np.meshgrid( *[np.arange(len(coord_eval)) for coord_eval in axes_evaluation]) eval_index = np.reshape(np.array(mesh_index), (3, -1)) run_index = np.arange(np.shape(eval_index)[1]) np.random.shuffle(run_index) sys.stdout.write(" ") for counter, point_index in enumerate(run_index): i, j, k = eval_index[:, point_index] eval_x = axes_evaluation[0][i] eval_y = axes_evaluation[1][j] eval_z = axes_evaluation[2][k] if dose_evaluation[i, j, k] < lower_dose_cutoff: continue distance = np.sqrt((xx_ref - eval_x)**2 + (yy_ref - eval_y)**2 + (zz_ref - eval_z)**2) dose_diff = dose_evaluation[i, j, k] - dose_reference gamma = np.min( np.sqrt((dose_diff / dose_threshold)**2 + (distance / distance_mm_threshold)**2)) gamma_array[i, j, k] = gamma if counter // 30 == counter / 30: percent_pass = str( np.round(calculate_pass_rate(gamma_array), decimals=1)) sys.stdout.write( "\rPercent Pass: {0}% | Percent Complete: {1:.2f}%".format( percent_pass, counter / np.shape(eval_index)[1] * 100)) sys.stdout.flush() return calculate_pass_rate(gamma_array)
def _convert_to_full_grid(grid, full_grid, mu_density): grid_xx, grid_yy = np.meshgrid(grid["mlc"], grid["jaw"]) full_grid_xx, full_grid_yy = np.meshgrid(full_grid["mlc"], full_grid["jaw"]) xx_from, xx_to = np.where( np.abs(full_grid_xx[None, 0, :] - grid_xx[0, :, None]) < 0.0001) yy_from, yy_to = np.where( np.abs(full_grid_yy[None, :, 0] - grid_yy[:, 0, None]) < 0.0001) full_grid_mu_density = np.zeros_like(full_grid_xx) full_grid_mu_density[ # pylint: disable=unsupported-assignment-operation np.ix_(yy_to, xx_to)] = mu_density[np.ix_(yy_from, xx_from)] return full_grid_mu_density
def get_dose_grid_structure_mask(structure_name, dcm_struct, dcm_dose): x_dose, y_dose, z_dose = xyz_axes_from_dataset(dcm_dose) xx_dose, yy_dose = np.meshgrid(x_dose, y_dose) points = np.swapaxes(np.vstack([xx_dose.ravel(), yy_dose.ravel()]), 0, 1) x_structure, y_structure, z_structure = pull_structure( structure_name, dcm_struct) structure_z_values = np.array([item[0] for item in z_structure]) mask = np.zeros((len(y_dose), len(x_dose), len(z_dose)), dtype=bool) for z_val in structure_z_values: structure_indices = _get_indices(z_structure, z_val) for structure_index in structure_indices: dose_index = int(np.where(z_dose == z_val)[0]) assert z_structure[structure_index][0] == z_dose[dose_index] structure_polygon = matplotlib.path.Path([ (x_structure[structure_index][i], y_structure[structure_index][i]) for i in range(len(x_structure[structure_index])) ]) mask[:, :, dose_index] = mask[:, :, dose_index] | ( structure_polygon.contains_points(points).reshape( len(y_dose), len(x_dose))) return mask
def create_transformed_mesh(width_data, length_data, factor_data): """Return factor data meshgrid.""" x = np.arange( np.floor(np.min(width_data)) - 1, np.ceil(np.max(width_data)) + 1, 0.1) y = np.arange( np.floor(np.min(length_data)) - 1, np.ceil(np.max(length_data)) + 1, 0.1) xx, yy = np.meshgrid(x, y) zz = spline_model_with_deformability( xx, convert2_ratio_perim_area(xx, yy), width_data, convert2_ratio_perim_area(width_data, length_data), factor_data, ) zz[xx > yy] = np.nan no_data_x = np.all(np.isnan(zz), axis=0) no_data_y = np.all(np.isnan(zz), axis=1) x = x[np.invert(no_data_x)] y = y[np.invert(no_data_y)] zz = zz[np.invert(no_data_y), :] zz = zz[:, np.invert(no_data_x)] return x, y, zz
def calc_mu_density_return_grid( mu, mlc, jaw, grid_resolution=__DEFAULT_GRID_RESOLUTION, max_leaf_gap=__DEFAULT_MAX_LEAF_GAP, leaf_pair_widths=__DEFAULT_LEAF_PAIR_WIDTHS, min_step_per_pixel=__DEFAULT_MIN_STEP_PER_PIXEL, ): """DEPRECATED. This is a temporary helper function to provide the old api. """ leaf_pair_widths = np.array(leaf_pair_widths) mu_density = calc_mu_density( mu, mlc, jaw, grid_resolution=grid_resolution, max_leaf_gap=max_leaf_gap, leaf_pair_widths=leaf_pair_widths, min_step_per_pixel=min_step_per_pixel, ) full_grid = get_grid(max_leaf_gap, grid_resolution, leaf_pair_widths) grid_xx, grid_yy = np.meshgrid(full_grid["mlc"], full_grid["jaw"]) return grid_xx, grid_yy, mu_density
def create_test_image( field_centre, field_side_lengths, field_penumbra, field_rotation, bb_centre, bb_diameter, bb_max_attenuation, ): field = wlutz_mocks.create_field_with_bb_func( field_centre, field_side_lengths, field_penumbra, field_rotation, bb_centre, bb_diameter, bb_max_attenuation, ) x = np.arange(-20, 20.1, 0.1) y = np.arange(-22, 22.1, 0.1) xx, yy = np.meshgrid(x, y) img = field(xx, yy) return x, y, img
def create_bb_attenuation_func(diameter, penumbra, max_attenuation): dx = diameter / 100 radius = diameter / 2 image_half_width = penumbra * 2 + radius x = np.arange(-image_half_width, image_half_width + dx, dx) xx, yy = np.meshgrid(x, x) with warnings.catch_warnings(): warnings.simplefilter("ignore") z = np.sqrt(radius**2 - xx**2 - yy**2) / radius z[np.isnan(z)] = 0 sig = profiles.scaled_penumbra_sig() * penumbra sig_pixel = sig / dx filtered = scipy.ndimage.gaussian_filter(z, sig_pixel) interp = scipy.interpolate.RegularGridInterpolator((x, x), filtered, bounds_error=False, fill_value=None) def attenuation(x, y): return 1 - interp((x, y)) * max_attenuation return attenuation
def dose_inside_cube(x_dose, y_dose, z_dose, dose, cube): """Find the dose just within the given cube. """ cube_definition = cubify(cube) print(cube_definition) vertices = cube_vertices(cube_definition) bounding_box = get_bounding_box(vertices) x_outside = (x_dose < bounding_box[1][0]) | (x_dose > bounding_box[1][1]) y_outside = (y_dose < bounding_box[0][0]) | (y_dose > bounding_box[0][1]) z_outside = (z_dose < bounding_box[2][0]) | (z_dose > bounding_box[2][1]) xx, yy, zz = np.meshgrid( x_dose[np.invert(x_outside)], y_dose[np.invert(y_outside)], z_dose[np.invert(z_outside)], ) where_x = np.where(np.invert(x_outside))[0] where_y = np.where(np.invert(y_outside))[0] where_z = np.where(np.invert(z_outside))[0] bounded_dose = dose[ where_y[0] : where_y[-1] + 1, where_x[0] : where_x[-1] + 1, where_z[0] : where_z[-1] + 1, ] points_to_test = np.array( [ [y, x, z, d] for y, x, z, d in zip( np.ravel(yy), np.ravel(xx), np.ravel(zz), np.ravel(bounded_dose) ) ] ) inside_cube = [ test_if_in_cube(point_test, cube_definition) for point_test in points_to_test[:, 0:3] ] points_inside_cube = points_to_test[inside_cube, :] ax = plot_cube(cube_definition) ax.scatter( points_inside_cube[:, 1], points_inside_cube[:, 0], points_inside_cube[:, 2], c=points_inside_cube[:, 3], alpha=0.4, ) return ax
def define_penumbra_points_at_origin(edge_lengths, penumbra): penumbra_range = np.linspace(-penumbra / 2, penumbra / 2, 11) def _each_edge(current_edge_length, orthogonal_edge_length): half_field_range = np.linspace(-orthogonal_edge_length / 4, orthogonal_edge_length / 4, 51) a_side_lookup = -current_edge_length / 2 + penumbra_range b_side_lookup = current_edge_length / 2 + penumbra_range current_axis_lookup = np.concatenate([a_side_lookup, b_side_lookup]) return current_axis_lookup, half_field_range edge_points_left_right = _each_edge(edge_lengths[0], edge_lengths[1]) edge_points_top_bot = _each_edge(edge_lengths[1], edge_lengths[0]) xx_left_right, yy_left_right = np.meshgrid(*edge_points_left_right) xx_top_bot, yy_top_bot = np.meshgrid(*edge_points_top_bot[::-1]) return xx_left_right, yy_left_right, xx_top_bot, yy_top_bot
def do_rotation(x_span, y_span, angle): """Generate a meshgrid and rotate it by `angle` degrees.""" radians = angle * np.pi / 180 rotation_matrix = np.array([[np.cos(radians), np.sin(radians)], [-np.sin(radians), np.cos(radians)]]) xx, yy = np.meshgrid(x_span, y_span, indexing="ij") return np.einsum("ji, mni -> jmn", rotation_matrix, np.dstack([xx, yy]))
def define_rotation_field_points_at_origin(edge_lengths, penumbra): x_half_range = edge_lengths[0] / 2 + penumbra / 2 y_half_range = edge_lengths[1] / 2 + penumbra / 2 num_x = np.ceil(x_half_range * 2 * 8) + 1 num_y = np.ceil(y_half_range * 2 * 8) + 1 x = np.linspace(-x_half_range, x_half_range, int(num_x)) y = np.linspace(-y_half_range, y_half_range, int(num_y)) xx, yy = np.meshgrid(x, y) xx_flat = np.ravel(xx) yy_flat = np.ravel(yy) inside = np.logical_and((np.abs(xx_flat) < x_half_range), (np.abs(yy_flat) < y_half_range)) xx_flat = xx_flat[np.invert(inside)] yy_flat = yy_flat[np.invert(inside)] return xx_flat, yy_flat
def run_wlutz( field, edge_lengths, penumbra, field_centre, field_rotation, find_bb=True, pixel_size=0.1, pylinac_versions=("v2.2.6", "v2.2.7"), ): centralised_straight_field = create_centralised_field( field, field_centre, field_rotation) half_x_range = edge_lengths[0] / 2 + penumbra * 3 half_y_range = edge_lengths[1] / 2 + penumbra * 3 x_range = np.arange(-half_x_range, half_x_range + pixel_size, pixel_size) y_range = np.arange(-half_y_range, half_y_range + pixel_size, pixel_size) xx_range, yy_range = np.meshgrid(x_range, y_range) centralised_image = centralised_straight_field(xx_range, yy_range) results = {} for key in pylinac_versions: pylinac_field_centre, pylinac_bb_centre = run_pylinac_with_class( VERSION_TO_CLASS_MAP[key], centralised_image, pixel_size, half_x_range, half_y_range, field_centre, field_rotation, find_bb=find_bb, ) results[key] = { "field_centre": pylinac_field_centre, "bb_centre": pylinac_bb_centre, } return results
def coords_from_xyz_axes(xyz_axes): """Converts a set of x, y and z axes of a regular grid (e.g. a DICOM pixel array) into an array of three grids whose voxels correspond to and contain the `x`, `y`, and `z` coordinates of the original grid. Parameters ---------- xyz_axes : tuple A tuple containing three `numpy.ndarray`s corresponding to the `x`, `y` and `z` axes of a given 3D grid - usually a DICOM dataset's pixel array. Returns ------- coords : ndarray An array containing three grids consisting of the `x`, 'y` and `z` coordinates of the corresponding grid (e.g. DICOM dataset's pixel array) from which the original axes were extracted. """ ZZ, YY, XX = np.meshgrid(xyz_axes[2], xyz_axes[1], xyz_axes[0], indexing="ij") coords = np.array((XX, YY, ZZ), dtype=np.float64) return coords
def create_point_combination(coords): mesh_index = np.meshgrid(*coords) point_combination = np.reshape(np.array(mesh_index), (3, -1)) return point_combination
def from_user_inputs( cls, axes_reference, dose_reference, axes_evaluation, dose_evaluation, dose_percent_threshold, distance_mm_threshold, lower_percent_dose_cutoff=20, interp_fraction=10, max_gamma=None, local_gamma=False, global_normalisation=None, skip_once_passed=False, random_subset=None, ram_available=None, quiet=False, ): if max_gamma is None: max_gamma = np.inf axes_reference, axes_evaluation = run_input_checks( axes_reference, dose_reference, axes_evaluation, dose_evaluation) dose_percent_threshold = expand_dims_to_1d(dose_percent_threshold) distance_mm_threshold = expand_dims_to_1d(distance_mm_threshold) if global_normalisation is None: global_normalisation = np.max(dose_reference) lower_dose_cutoff = lower_percent_dose_cutoff / 100 * global_normalisation maximum_test_distance = np.max(distance_mm_threshold) * max_gamma evaluation_interpolation = scipy.interpolate.RegularGridInterpolator( axes_evaluation, np.array(dose_evaluation), bounds_error=False, fill_value=np.inf, ) dose_reference = np.array(dose_reference) reference_dose_above_threshold = dose_reference >= lower_dose_cutoff mesh_axes_reference = np.meshgrid(*axes_reference, indexing="ij") flat_mesh_axes_reference = np.array( [np.ravel(item) for item in mesh_axes_reference]) reference_points_to_calc = reference_dose_above_threshold reference_points_to_calc = np.ravel(reference_points_to_calc) if random_subset is not None: to_calc_index = np.where(reference_points_to_calc)[0] np.random.shuffle(to_calc_index) random_subset_to_calc = np.full_like(reference_points_to_calc, False, dtype=bool) random_subset_to_calc[ # pylint: disable=unsupported-assignment-operation to_calc_index[0:random_subset]] = True reference_points_to_calc = random_subset_to_calc flat_dose_reference = np.ravel(dose_reference) return cls( flat_mesh_axes_reference, flat_dose_reference, reference_points_to_calc, dose_percent_threshold, distance_mm_threshold, evaluation_interpolation, interp_fraction, max_gamma, lower_dose_cutoff, maximum_test_distance, global_normalisation, local_gamma, skip_once_passed, ram_available, quiet, )