Exemple #1
0
def get_contours_from_mask(x_grid, y_grid, mask):
    fig, ax = plt.subplots()
    with warnings.catch_warnings():
        warnings.simplefilter("ignore", UserWarning)
        cs = ax.contour(x_grid, y_grid, mask, [0])

    contours = [path.vertices for path in cs.collections[0].get_paths()]
    plt.close(fig)

    return contours
Exemple #2
0
def multi_slice_viewer(volume, dx, dy):
    # remove_keymap_conflicts({'j', 'k'})
    fig, ax = plt.subplots()
    ax.volume = volume
    ax.index = volume.shape[2] // 2
    print(ax.index)
    extent = (0, 0 + (volume.shape[1] * dx), 0, 0 + (volume.shape[0] * dy))
    ax.imshow(volume[:, :, ax.index], extent=extent)
    ax.set_xlabel("x distance [mm]")
    ax.set_ylabel("y distance [mm]")
    ax.set_title("item=" + str(ax.index))
    fig.suptitle("Axial view", fontsize=16)
    fig.canvas.mpl_connect("key_press_event", process_key_axial)
Exemple #3
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
Exemple #4
0
    def plot(self, show_peaks: bool = True):
        """Plot the profile.

        Parameters
        ----------
        show_peaks : bool
            Whether to plot the peak locations as well. Will not show if a peak search has
            not yet been done.
        """
        _, ax = plt.subplots()
        ax.plot(self.values)
        if show_peaks:
            peaks_x = [peak.idx for peak in self.peaks]
            peaks_y = [peak.value for peak in self.peaks]
            ax.plot(peaks_x, peaks_y, "go")
Exemple #5
0
    def plot2axes(
        self,
        axes=None,
        edgecolor: str = "black",
        fill: bool = False,
        plot_peaks: bool = True,
    ):
        """Add 2 circles to the axes: one at the maximum and minimum radius of the ROI.

        See Also
        --------
        :meth:`~pylinac.core.profile.CircleProfile.plot2axes` : Further parameter info.
        """
        if axes is None:
            _, axes = plt.subplots()
            axes.imshow(self.image_array)
        axes.add_patch(
            matplotlib.patches.Circle(
                (self.center.x, self.center.y),
                edgecolor=edgecolor,
                radius=self.radius * (1 + self.width_ratio),
                fill=fill,
            )
        )
        axes.add_patch(
            matplotlib.patches.Circle(
                (self.center.x, self.center.y),
                edgecolor=edgecolor,
                radius=self.radius * (1 - self.width_ratio),
                fill=fill,
            )
        )
        if plot_peaks:
            x_locs = [peak.x for peak in self.peaks]
            y_locs = [peak.y for peak in self.peaks]
            axes.autoscale(enable=False)
            axes.scatter(x_locs, y_locs, s=20, marker="x", c=edgecolor)
Exemple #6
0
    def plot2axes(  # pylint: disable = arguments-differ
        self,
        axes=None,
        edgecolor: str = "black",
        fill: bool = False,
        plot_peaks: bool = True,
    ):
        """Plot the circle to an axes.

        Parameters
        ----------
        axes : matplotlib.Axes, None
            The axes to plot on. If None, will create a new figure of the image array.
        edgecolor : str
            Color of the Circle; must be a valid matplotlib color.
        fill : bool
            Whether to fill the circle. matplotlib keyword.
        plot_peaks : bool
            If True, plots the found peaks as well.
        """
        if axes is None:
            _, axes = plt.subplots()
            axes.imshow(self.image_array)
        axes.add_patch(
            matplotlib.patches.Circle(
                (self.center.x, self.center.y),
                edgecolor=edgecolor,
                radius=self.radius,
                fill=fill,
            )
        )
        if plot_peaks:
            x_locs = [peak.x for peak in self.peaks]
            y_locs = [peak.y for peak in self.peaks]
            axes.autoscale(enable=False)
            axes.scatter(x_locs, y_locs, s=40, marker="x", c=edgecolor)
def plot_and_save_results(
    reference_mudensity,
    evaluation_mudensity,
    gamma,
    gamma_options,
    png_record_directory,
    header_text="",
    footer_text="",
):
    reference_filepath = png_record_directory.joinpath("reference.png")
    evaluation_filepath = png_record_directory.joinpath("evaluation.png")
    diff_filepath = png_record_directory.joinpath("diff.png")
    gamma_filepath = png_record_directory.joinpath("gamma.png")

    diff = evaluation_mudensity - reference_mudensity

    imageio.imwrite(reference_filepath, reference_mudensity)
    imageio.imwrite(evaluation_filepath, evaluation_mudensity)
    imageio.imwrite(diff_filepath, diff)
    imageio.imwrite(gamma_filepath, gamma)

    largest_mu_density = np.max(
        [np.max(evaluation_mudensity),
         np.max(reference_mudensity)])
    largest_diff = np.max(np.abs(diff))

    widths = [1, 1]
    heights = [0.5, 1, 1, 1, 0.4]
    gs_kw = dict(width_ratios=widths, height_ratios=heights)

    fig, axs = plt.subplots(5, 2, figsize=(10, 16), gridspec_kw=gs_kw)
    gs = axs[0, 0].get_gridspec()

    for ax in axs[0, 0:]:
        ax.remove()

    for ax in axs[1, 0:]:
        ax.remove()

    for ax in axs[4, 0:]:
        ax.remove()

    ax_header = fig.add_subplot(gs[0, :])
    ax_hist = fig.add_subplot(gs[1, :])
    ax_footer = fig.add_subplot(gs[4, :])

    ax_header.axis("off")
    ax_footer.axis("off")

    ax_header.text(0, 0, header_text, ha="left", wrap=True, fontsize=21)
    ax_footer.text(0,
                   1,
                   footer_text,
                   ha="left",
                   va="top",
                   wrap=True,
                   fontsize=6)

    plt.sca(axs[2, 0])
    pymedphys.mudensity.display(GRID,
                                reference_mudensity,
                                vmin=0,
                                vmax=largest_mu_density)
    axs[2, 0].set_title("Reference MU Density")

    plt.sca(axs[2, 1])
    pymedphys.mudensity.display(GRID,
                                evaluation_mudensity,
                                vmin=0,
                                vmax=largest_mu_density)
    axs[2, 1].set_title("Evaluation MU Density")

    plt.sca(axs[3, 0])
    pymedphys.mudensity.display(GRID,
                                diff,
                                cmap="seismic",
                                vmin=-largest_diff,
                                vmax=largest_diff)
    plt.title("Evaluation - Reference")

    plt.sca(axs[3, 1])
    pymedphys.mudensity.display(GRID, gamma, cmap="coolwarm", vmin=0, vmax=2)
    plt.title("Local Gamma | "
              f"{gamma_options['dose_percent_threshold']}%/"
              f"{gamma_options['distance_mm_threshold']}mm")

    plt.sca(ax_hist)
    plot_gamma_hist(
        gamma,
        gamma_options["dose_percent_threshold"],
        gamma_options["distance_mm_threshold"],
    )

    return fig
Exemple #8
0
def merge_view_filtrot(volume, dx, dy):

    volume_resort = np.copy(
        volume
    )  # this will hold the resorted volume 0 to 3 clockwise
    junctions_comb = []
    peaks_figs_comb = []

    # we need to create 4 matches

    # 0,1,2,3 will be tagged top left, top right, bottom right, bottom left
    for i in range(0, int(np.shape(volume)[2])):
        diag_stack = [
            0,
            0,
            0,
            0,
        ]  # we will sum along one direction whichever is biggest will tag the file
        for j in range(0, int(min([np.shape(volume)[0], np.shape(volume)[1]]) / 2)):
            # print('j=',j,int(np.shape(volume)[0] / 2)+j, int(np.shape(volume)[1] / 2)+j)
            diag_stack[0] = (
                diag_stack[0]
                + volume[
                    int(np.shape(volume)[0] / 2) - j,
                    int(np.shape(volume)[1] / 2) - j,
                    i,
                ]
            )
            diag_stack[1] = (
                diag_stack[1]
                + volume[
                    int(np.shape(volume)[0] / 2) - j,
                    int(np.shape(volume)[1] / 2) + j,
                    i,
                ]
            )
            diag_stack[2] = (
                diag_stack[2]
                + volume[
                    int(np.shape(volume)[0] / 2) + j,
                    int(np.shape(volume)[1] / 2) + j,
                    i,
                ]
            )
            diag_stack[3] = (
                diag_stack[3]
                + volume[
                    int(np.shape(volume)[0] / 2) + j,
                    int(np.shape(volume)[1] / 2) - j,
                    i,
                ]
            )

        volume_resort[:, :, np.argmax(diag_stack)] = volume[:, :, i]

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

    # creating vector for processing (1 horizontal & 1 vertical)
    amplitude_horz = np.zeros(
        (volume_resort.shape[1], volume_resort.shape[2])
    )  # 1 if it is vertical 0 if the bars are horizontal
    amplitude_vert = np.zeros((volume_resort.shape[0], volume_resort.shape[2]))

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

    ampl_resamp_y1 = np.zeros(
        ((volume_resort.shape[0]) * 10, int(volume_resort.shape[2] / 2))
    )
    ampl_resamp_y2 = np.zeros(
        ((volume_resort.shape[0]) * 10, int(volume_resort.shape[2] / 2))
    )

    ampl_resamp_x1 = np.zeros(
        ((volume_resort.shape[1]) * 10, int(volume_resort.shape[2] / 2))
    )
    ampl_resamp_x2 = np.zeros(
        ((volume_resort.shape[1]) * 10, int(volume_resort.shape[2] / 2))
    )

    amplitude_horz[:, 0] = volume_resort[
        int(volume_resort.shape[0] / 3.25), :, 0
    ]  # for profile 1
    amplitude_horz[:, 1] = volume_resort[
        int(volume_resort.shape[0] / 3.25), :, 1
    ]  # for profile 1
    amplitude_horz[:, 3] = volume_resort[
        int(volume_resort.shape[0]) - int(volume_resort.shape[0] / 3.25), :, 2
    ]  # the numbers here are reversed because we are going to slide the second graph (the overlay) to minimize the error  #for profile 2
    amplitude_horz[:, 2] = volume_resort[
        int(volume_resort.shape[0]) - int(volume_resort.shape[0] / 3.25), :, 3
    ]

    amplitude_vert[:, 0] = volume_resort[
        :, int(volume_resort.shape[1]) - int(volume_resort.shape[1] / 2.8), 1
    ]  # the numbers here are reversed because we are going to slide the second graph (the overlay) to minimize the error #for profile 3
    amplitude_vert[:, 1] = volume_resort[
        :, int(volume_resort.shape[1]) - int(volume_resort.shape[1] / 2.8), 2
    ]
    amplitude_vert[:, 3] = volume_resort[
        :, int(volume_resort.shape[1] / 2.8), 3
    ]  # for profile 4
    amplitude_vert[:, 2] = volume_resort[:, int(volume_resort.shape[1] / 2.8), 0]

    plt.figure()
    for item in tqdm(range(0, int(volume.shape[2] / 2))):
        merge_vol = merge_vol + volume[:, :, item]

        data_samp = amplitude_vert[:, item]
        ampl_resamp_y1[:, item] = signal.resample(
            data_samp, int(np.shape(amplitude_vert)[0]) * 10
        )
        data_samp = amplitude_horz[:, item]
        ampl_resamp_x1[:, item] = signal.resample(
            data_samp, int(np.shape(amplitude_horz)[0]) * 10
        )

    for item in tqdm(range(int(volume.shape[2] / 2), volume.shape[2])):
        merge_vol = merge_vol + volume[:, :, item]
        data_samp = amplitude_vert[:, item]
        ampl_resamp_y2[:, item - int(volume.shape[2] / 2)] = signal.resample(
            data_samp, int(np.shape(amplitude_vert)[0]) * 10
        )
        data_samp = amplitude_horz[:, item]
        ampl_resamp_x2[:, item - int(volume.shape[2] / 2)] = signal.resample(
            data_samp, int(np.shape(amplitude_horz)[0]) * 10
        )

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

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

    ax.imshow(merge_vol, extent=extent, aspect="auto")
    ax.set_aspect("equal", "box")
    ax.set_xlabel("x distance [mm]")
    ax.set_ylabel("y distance [mm]")
    fig.suptitle("Merged volume", fontsize=16)

    ax.hlines(dy * int(volume_resort.shape[0] / 3.25), 0, dx * volume_resort.shape[1])
    ax.text(
        dx * int(volume_resort.shape[1] / 2.25),
        dy * int(volume_resort.shape[0] / 3),
        "Profile 2",
    )

    ax.hlines(
        dy * int(volume_resort.shape[0]) - dy * int(volume_resort.shape[0] / 3.25),
        0,
        dx * volume_resort.shape[1],
    )
    ax.text(
        dx * int(volume_resort.shape[1] / 2.25),
        dy * int(volume_resort.shape[0]) - dy * int(volume_resort.shape[0] / 3.5),
        "Profile 1",
    )

    ax.vlines(dx * int(volume_resort.shape[1] / 2.8), 0, dy * volume_resort.shape[0])
    ax.text(
        dx * int(volume_resort.shape[1] / 3.1),
        dy * int(volume_resort.shape[0] / 1.8),
        "Profile 4",
        rotation=90,
    )

    ax.vlines(
        dx * int(volume_resort.shape[1]) - dx * int(volume_resort.shape[1] / 2.8),
        0,
        dy * volume_resort.shape[0],
    )
    ax.text(
        dx * int(volume_resort.shape[1]) - dx * int(volume_resort.shape[1] / 2.9),
        dy * int(volume_resort.shape[0] / 1.8),
        "Profile 3",
        rotation=90,
    )
    # plt.show()

    peaks, peak_type, peak_figs = pffr.peak_find_fieldrot(
        ampl_resamp_x1, dx, "Profile 1"
    )
    junction_figs = minFR.minimize_junction_fieldrot(
        ampl_resamp_x1, peaks, peak_type, dx / 10, "Profile 1"
    )
    peaks_figs_comb.append(peak_figs)
    junctions_comb.append(junction_figs)

    peaks, peak_type, peak_figs = pffr.peak_find_fieldrot(
        ampl_resamp_x2, dx, "Profile 2"
    )
    junction_figs = minFR.minimize_junction_fieldrot(
        ampl_resamp_x2, peaks, peak_type, dx / 10, "Profile 2"
    )
    peaks_figs_comb.append(peak_figs)
    junctions_comb.append(junction_figs)

    peaks, peak_type, peak_figs = pffr.peak_find_fieldrot(
        ampl_resamp_y1, dy, "Profile 3"
    )
    junction_figs = minFR.minimize_junction_fieldrot(
        ampl_resamp_y1, peaks, peak_type, dy / 10, "Profile 3"
    )
    peaks_figs_comb.append(peak_figs)
    junctions_comb.append(junction_figs)

    peaks, peak_type, peak_figs = pffr.peak_find_fieldrot(
        ampl_resamp_y2, dy, "Profile 4"
    )
    junction_figs = minFR.minimize_junction_fieldrot(
        ampl_resamp_y2, peaks, peak_type, dy / 10, "Profile 4"
    )
    peaks_figs_comb.append(peak_figs)
    junctions_comb.append(junction_figs)

    return fig, peaks_figs_comb, junctions_comb
Exemple #9
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