Exemplo n.º 1
0
 def _indices_interp(self):
     """Interpolated values of the profile index data."""
     return np.linspace(
         start=0,
         stop=len(self.values) - 1,
         num=(len(self.values) - 1) * self.interpolation_factor,
     )
Exemplo n.º 2
0
def create_control_point_sequence(beam, beam_collimation, rotation_direction,
                                  dose_rate, gantry, coll, nominal_energy):
    num_cps = len(gantry)
    meterset_weight = np.linspace(0, 1, num_cps)

    cp_bounds = bounding_control_points(beam, beam_collimation,
                                        rotation_direction, dose_rate)

    control_point_sequence = pydicom.Sequence(
        [copy.deepcopy(cp_bounds["first"])])

    control_point_sequence[0].GantryAngle = str(gantry[0])
    control_point_sequence[0].BeamLimitingDeviceAngle = str(coll[0])
    control_point_sequence[0].NominalBeamEnergy = nominal_energy

    for i in range(1, num_cps - 1):
        cp = copy.deepcopy(cp_bounds["mid"])

        cp.GantryAngle = str(gantry[i])
        cp.BeamLimitingDeviceAngle = str(coll[i])
        cp.CumulativeMetersetWeight = str(round(meterset_weight[i], 6))
        cp.ControlPointIndex = str(i)

        control_point_sequence.append(cp)

    cp = copy.deepcopy(cp_bounds["last"])
    cp.GantryAngle = str(gantry[-1])
    cp.BeamLimitingDeviceAngle = str(coll[-1])
    cp.ControlPointIndex = str(num_cps - 1)

    control_point_sequence.append(cp)

    return control_point_sequence
Exemplo n.º 3
0
def visual_circle_and_ellipse(insert_x, insert_y, width, length,
                              circle_centre):

    t = np.linspace(0, 2 * np.pi)
    circle = {
        "x": width / 2 * np.sin(t) + circle_centre[0],
        "y": width / 2 * np.cos(t) + circle_centre[1],
    }

    x_shift, y_shift, rotation_angle = visual_alignment_of_equivalent_ellipse(
        insert_x, insert_y, width, length, None)

    rotation_matrix = np.array([
        [np.cos(rotation_angle), -np.sin(rotation_angle)],
        [np.sin(rotation_angle),
         np.cos(rotation_angle)],
    ])

    ellipse = np.array([length / 2 * np.sin(t), width / 2 * np.cos(t)]).T

    rotated_ellipse = ellipse @ rotation_matrix

    translated_ellipse = rotated_ellipse + np.array([y_shift, x_shift])
    ellipse = {"x": translated_ellipse[:, 1], "y": translated_ellipse[:, 0]}

    return circle, ellipse
Exemplo n.º 4
0
    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
Exemplo n.º 5
0
def calculate_coordinates_shell_2d(distance, distance_step_size):
    """Create points along the circumference of a circle. The spacing
    between points is not larger than the defined distance_step_size
    """
    amount_to_check = np.ceil(2 * np.pi * distance / distance_step_size).astype(int) + 1
    theta = np.linspace(0, 2 * np.pi, amount_to_check + 1)[:-1:]
    x_coords = distance * np.cos(theta)
    y_coords = distance * np.sin(theta)

    return (x_coords, y_coords)
Exemplo n.º 6
0
def calculate_coordinates_shell_3d(distance, distance_step_size):
    """Create points along the surface of a sphere (a shell) where no gap
    between points is larger than the defined distance_step_size"""

    number_of_rows = np.ceil(np.pi * distance / distance_step_size).astype(int) + 1

    elevation = np.linspace(0, np.pi, number_of_rows)
    row_radii = distance * np.sin(elevation)
    row_circumference = 2 * np.pi * row_radii
    amount_in_row = np.ceil(row_circumference / distance_step_size).astype(int) + 1

    x_coords = []
    y_coords = []
    z_coords = []
    for i, phi in enumerate(elevation):
        azimuth = np.linspace(0, 2 * np.pi, amount_in_row[i] + 1)[:-1:]
        x_coords.append(distance * np.sin(phi) * np.cos(azimuth))
        y_coords.append(distance * np.sin(phi) * np.sin(azimuth))
        z_coords.append(distance * np.cos(phi) * np.ones_like(azimuth))

    return (np.hstack(x_coords), np.hstack(y_coords), np.hstack(z_coords))
Exemplo n.º 7
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
Exemplo n.º 8
0
def merge_view_horz(volume, dx, dy):
    junctions = []

    # creating merged volume
    merge_vol = np.zeros((volume.shape[0], volume.shape[1]))

    # creating vector for processing along cols (one row)
    amplitude = np.zeros(
        (volume.shape[0],
         volume.shape[2]))  # 1 if it is vertical 0 if the bars are horizontal

    y = np.linspace(0,
                    0 + (volume.shape[0] * dy),
                    volume.shape[0],
                    endpoint=False)  # definition of the distance axis
    # x = np.arange(0,) #definition of the distance axis

    # merging the two images together
    ampl_resamp = np.zeros(((volume.shape[0]) * 10, volume.shape[2]))
    # amp_peak = np.zeros((volume.shape[0]) * 10)

    for item in tqdm(range(0, volume.shape[2])):
        merge_vol = merge_vol + volume[:, :, item]
        amplitude[:, item] = volume[:, int(volume.shape[1] / 2), item]
        ampl_resamp[:, item] = signal.resample(
            amplitude[:, item],
            int(len(amplitude)) * 10)  # resampling the amplitude vector
        # amp_peak = amp_peak + ampl_resamp[:, item] / volume.shape[2]

    fig, ax = plt.subplots(nrows=2, squeeze=True, figsize=(6, 8))

    extent = (0, 0 + (volume.shape[1] * dx), 0, 0 + (volume.shape[0] * dy))

    ax[0].imshow(merge_vol, extent=extent, aspect="auto")
    ax[0].set_xlabel("x distance [mm]")
    ax[0].set_ylabel("y distance [mm]")

    ax[1].plot(y, amplitude, label="Amplitude profile")
    ax[1].set_ylabel("amplitude")
    ax[1].set_xlabel("y distance [mm]")
    ax[1].legend()
    fig.suptitle("Merged volume", fontsize=16)

    # peaks, peak_type, peak_figs = peak_find(ampl_resamp, dy)
    peaks, peak_type, peak_figs = pf.peak_find(ampl_resamp, dy)
    # junction_figs = minimize_junction_Y(ampl_resamp, peaks, peak_type, dy / 10)
    junction_figs = minY.minimize_junction_Y(ampl_resamp, peaks, peak_type,
                                             dy / 10)
    junctions.append(junction_figs)

    return fig, peak_figs, junctions
Exemplo 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
Exemplo n.º 10
0
def resample_contour(contour, n=51):
    tck, _ = splprep([contour[0], contour[1], contour[2]], s=0, k=1)
    new_points = splev(np.linspace(0, 1, n), tck)

    return new_points
Exemplo n.º 11
0
def peak_find(ampl_resamp, dx):
    peak_figs = []
    peaks = []
    peak_type = []
    for j in range(0, ampl_resamp.shape[1] - 1):
        amp_base_res = signal.convolve(ampl_resamp[:, j],
                                       ampl_resamp[:, j],
                                       mode="full")
        amp_base_res = signal.resample(amp_base_res / np.amax(amp_base_res),
                                       int(np.ceil(len(amp_base_res) / 2)))
        for k in range(j + 1, ampl_resamp.shape[1]):
            amp_overlay_res = signal.convolve(ampl_resamp[:, k],
                                              ampl_resamp[:, k],
                                              mode="full")
            amp_overlay_res = signal.resample(
                amp_overlay_res / np.amax(amp_overlay_res),
                int(np.ceil(len(amp_overlay_res) / 2)),
            )
            # amp_overlay_res = signal.savgol_filter(ampl_resamp[:, k], 1501, 1)

            peak1, _ = find_peaks(amp_base_res, prominence=0.5)
            peak2, _ = find_peaks(amp_overlay_res, prominence=0.5)

            if (
                    abs(peak2 - peak1) < 2500
            ):  # if the two peaks are separated the two fields are not adjacent.
                amp_peak = ampl_resamp[:, j] + ampl_resamp[:, k]
                x = np.linspace(
                    0,
                    0 + (len(amp_peak) * dx / 10),
                    len(amp_peak),
                    endpoint=False)  # definition of the distance axis

                peak_pos, _ = find_peaks(
                    signal.savgol_filter(
                        amp_peak[min(peak1[0], peak2[0]
                                     ):max(peak1[0], peak2[0])],
                        201,
                        3,
                    ),
                    prominence=0.010,
                )
                pos_prominence = signal.peak_prominences(
                    signal.savgol_filter(
                        amp_peak[min(peak1[0], peak2[0]
                                     ):max(peak1[0], peak2[0])],
                        201,
                        3,
                    ),
                    peak_pos,
                )
                # print('#peaks pos det=', len(peak_pos), peak_pos)
                # print('#pos peaks prominence=', pos_prominence[0])
                peak_neg, _ = find_peaks(
                    signal.savgol_filter(
                        -amp_peak[min(peak1[0], peak2[0]
                                      ):max(peak1[0], peak2[0])],
                        201,
                        3,
                    ),
                    prominence=0.010,
                )
                neg_prominence = signal.peak_prominences(
                    signal.savgol_filter(
                        -amp_peak[min(peak1[0], peak2[0]
                                      ):max(peak1[0], peak2[0])],
                        201,
                        3,
                    ),
                    peak_neg,
                )
                # print('#peaks neg det=',len(peak_neg),peak_neg)
                # print('#neg peaks prominence=', neg_prominence[0])
                # we now need to select the peak with the largest prominence positve or negative
                # we add all the peaks and prominences toghether
                peaks_all = np.concatenate((peak_pos, peak_neg), axis=None)
                prom_all = np.concatenate(
                    (pos_prominence[0], neg_prominence[0]), axis=None)
                # print('all peaks',peaks_all,prom_all)

                if peaks_all.size != 0:
                    peak = peaks_all[np.argmax(prom_all)]
                    if peak in peak_pos:
                        peak_type.append(1)
                        peaks.append(min(peak1[0], peak2[0]) + peak)
                        # print('pos peak')
                    elif peak in peak_neg:
                        peak_type.append(0)
                        peaks.append(min(peak1[0], peak2[0]) + peak)
                        # print('neg peak')

                    fig = plt.figure(figsize=(10, 6))
                    plt.plot(x, amp_peak, label="Total amplitude profile")
                    plt.plot(
                        x[min(peak1[0], peak2[0]) + peak],
                        amp_peak[min(peak1[0], peak2[0]) + peak],
                        "x",
                        label="Peaks detected",
                    )
                    plt.ylabel("amplitude [a.u.]")
                    plt.xlabel("distance [mm]")
                    plt.legend()
                    fig.suptitle("Junctions", fontsize=16)
                    peak_figs.append(fig)

                elif peaks_all.size == 0:
                    peaks.append(0)
                    peak_type.append(0)
                    print("no peak has been found")
                    fig = plt.figure(figsize=(10, 6))
                    plt.plot(x, amp_peak, label="Total amplitude profile")
                    # plt.plot(x[min(peak1[0], peak2[0]) + peak], amp_peak[min(peak1[0], peak2[0]) + peak], "x",
                    #          label='Peaks detected')
                    plt.ylabel("amplitude [a.u.]")
                    plt.xlabel("distance [mm]")
                    plt.legend()
                    fig.suptitle("Junctions", fontsize=16)
                    peak_figs.append(fig)

            # else:
            # print(j, k, 'the data is not contiguous finding another curve in dataset')

    # print('peaks_here=',peaks)
    return peaks, peak_type, peak_figs
Exemplo n.º 12
0
 def _indices(self):
     """Values of the profile index data."""
     return np.linspace(start=0, stop=len(self.values) - 1, num=len(self.values))
Exemplo n.º 13
0
 def _radii(self):
     return np.linspace(
         start=self.radius * (1 - self.width_ratio),
         stop=self.radius * (1 + self.width_ratio),
         num=self.num_profiles,
     )
Exemplo n.º 14
0
def image_analysis_figure(
    x,
    y,
    img,
    bb_centre,
    field_centre,
    field_rotation,
    bb_diameter,
    edge_lengths,
    penumbra,
    units="(mm)",
):
    field = imginterp.create_interpolated_field(x, y, img)

    x_half_bound = edge_lengths[0] / 2 + penumbra * 3
    y_half_bound = edge_lengths[1] / 2 + penumbra * 3

    x_axis = np.linspace(-x_half_bound, x_half_bound, 200)
    y_axis = np.linspace(-y_half_bound, y_half_bound, 200)

    field_transform = interppoints.translate_and_rotate_transform(
        field_centre, field_rotation)
    x_field_interp, y_field_interp = createaxis.transform_axis(
        x_axis, y_axis, field_transform)

    if bb_centre is not None:
        bb_transform = interppoints.translate_and_rotate_transform(
            bb_centre, 0)
        x_bb_interp, y_bb_interp = createaxis.transform_axis(
            x_axis, y_axis, bb_transform)
    else:
        x_bb_interp, y_bb_interp = None, None

    fig, axs = plt.subplots(ncols=2, nrows=4, figsize=(12, 15))
    gs = axs[0, 0].get_gridspec()
    for ax in np.ravel(axs[0:2, 0:2]):
        ax.remove()

    ax_big = fig.add_subplot(gs[0:2, 0:2])

    axs[0, 0] = ax_big

    pixel_value_label = "Scaled image pixel value"

    image_with_overlays(
        fig,
        ax_big,
        x,
        y,
        img,
        field_transform,
        bb_centre,
        field_centre,
        bb_diameter,
        edge_lengths,
        x_field_interp,
        y_field_interp,
        x_bb_interp,
        y_bb_interp,
        pixel_value_label,
        units=units,
    )

    profile_flip_plot(axs[2, 0], x_axis, field(*x_field_interp))
    axs[2, 0].set_xlim([
        edge_lengths[0] / 2 - penumbra * 2, edge_lengths[0] / 2 + penumbra * 2
    ])
    axs[2, 0].set_title("Flipped profile about field centre [field x-axis]")
    axs[2, 0].set_xlabel(f"Distance from field centre {units}")
    axs[2, 0].set_ylabel(pixel_value_label)

    profile_flip_plot(axs[2, 1], y_axis, field(*y_field_interp))
    axs[2, 1].set_xlim([
        edge_lengths[1] / 2 - penumbra * 2, edge_lengths[1] / 2 + penumbra * 2
    ])
    axs[2, 1].set_title("Flipped profile about field centre [field y-axis]")
    axs[2, 1].set_xlabel(f"Distance from field centre {units}")
    axs[2, 1].set_ylabel(pixel_value_label)

    if bb_centre is not None:
        x_mask = (x_axis >= -bb_diameter / 2 - penumbra) & (
            x_axis <= bb_diameter / 2 + penumbra)
        profile_flip_plot(axs[3, 0], x_axis[x_mask],
                          field(*x_bb_interp)[x_mask])
        axs[3, 0].set_xlim(
            [-bb_diameter / 2 - penumbra, bb_diameter / 2 + penumbra])
        axs[3, 0].set_title("Flipped profile about BB centre [panel x-axis]")
        axs[3, 0].set_xlabel(f"Displacement from BB centre {units}")
        axs[3, 0].set_ylabel(pixel_value_label)

        y_mask = (y_axis >= -bb_diameter / 2 - penumbra) & (
            y_axis <= bb_diameter / 2 + penumbra)
        profile_flip_plot(axs[3, 1], y_axis[y_mask],
                          field(*y_bb_interp)[y_mask])
        axs[3, 1].set_xlim(
            [-bb_diameter / 2 - penumbra, bb_diameter / 2 + penumbra])
        axs[3, 1].set_title("Flipped profile about BB centre [panel y-axis]")
        axs[3, 1].set_xlabel(f"Displacement from BB centre {units}")
        axs[3, 1].set_ylabel(pixel_value_label)

    plt.tight_layout()

    return fig, axs
Exemplo n.º 15
0
def image_with_overlays(
    fig,
    ax,
    x,
    y,
    img,
    field_transform,
    bb_centre,
    field_centre,
    bb_diameter,
    edge_lengths,
    x_field_interp,
    y_field_interp,
    x_bb_interp,
    y_bb_interp,
    pixel_value_label,
    units="(mm)",
):
    rect_crosshair_dx = [
        -edge_lengths[0] / 2,
        edge_lengths[0],
        -edge_lengths[0],
        edge_lengths[0],
    ]
    rect_crosshair_dy = [
        -edge_lengths[1] / 2, edge_lengths[1], 0, -edge_lengths[1]
    ]

    rect_dx = [-edge_lengths[0] / 2, 0, edge_lengths[0], 0, -edge_lengths[0]]
    rect_dy = [-edge_lengths[1] / 2, edge_lengths[1], 0, -edge_lengths[1], 0]

    c = ax.contourf(x, y, img, 100)
    fig.colorbar(c, ax=ax, label=pixel_value_label)

    ax.plot(*draw_by_diff(rect_dx, rect_dy, field_transform), "k", lw=3)
    ax.plot(*draw_by_diff(rect_crosshair_dx, rect_crosshair_dy,
                          field_transform),
            "k",
            lw=1)

    ax.plot(x_field_interp[0], x_field_interp[1], "k", lw=0.5, alpha=0.3)
    ax.plot(y_field_interp[0], y_field_interp[1], "k", lw=0.5, alpha=0.3)

    if bb_centre is not None:
        bb_radius = bb_diameter / 2
        bb_crosshair = np.array([-bb_radius, bb_radius])

        t = np.linspace(0, 2 * np.pi)
        circle_x_origin = bb_diameter / 2 * np.sin(t)
        circle_y_origin = bb_diameter / 2 * np.cos(t)

        circle_x = circle_x_origin + bb_centre[0]
        circle_y = circle_y_origin + bb_centre[1]

        ax.plot([bb_centre[0]] * 2, bb_crosshair + bb_centre[1], "k", lw=1)
        ax.plot(bb_crosshair + bb_centre[0], [bb_centre[1]] * 2, "k", lw=1)

        ax.plot(circle_x, circle_y, "k", lw=3)

        ax.plot(x_bb_interp[0], x_bb_interp[1], "k", lw=0.5, alpha=0.3)
        ax.plot(y_bb_interp[0], y_bb_interp[1], "k", lw=0.5, alpha=0.3)

        ax.plot(
            [field_centre[0], bb_centre[0]],
            [field_centre[1], bb_centre[1]],
            c="C3",
            lw=3,
        )

    ax.axis("equal")
    long_edge = np.sqrt(np.sum((np.array(edge_lengths))**2))
    long_edge_fraction = long_edge * 0.6

    ax.set_xlim([
        field_centre[0] - long_edge_fraction,
        field_centre[0] + long_edge_fraction
    ])
    ax.set_ylim([
        field_centre[1] - long_edge_fraction,
        field_centre[1] + long_edge_fraction
    ])

    ax.set_xlabel(f"iView panel absolute x-pos {units}")
    ax.set_ylabel(f"iView panel absolute y-pos {units}")