Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
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
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
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]))
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
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
Ejemplo n.º 13
0
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
Ejemplo n.º 14
0
def create_point_combination(coords):
    mesh_index = np.meshgrid(*coords)
    point_combination = np.reshape(np.array(mesh_index), (3, -1))

    return point_combination
Ejemplo n.º 15
0
    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,
        )