Exemplo n.º 1
0
 def find_mlc_peak(self, mlc_center):
     """Determine the center of the picket."""
     mlc_rows = np.arange(mlc_center - self.sample_width, mlc_center + self.sample_width + 1)
     if self.settings.orientation == orientations['UD']:
         pix_vals = np.median(self.picket_array[mlc_rows, :], axis=0)
     else:
         pix_vals = np.median(self.picket_array[:, mlc_rows], axis=1)
     if max(pix_vals) > np.percentile(self.picket_array, 80):
         prof = SingleProfile(pix_vals)
         fw80mc = prof.fwxm_center(70, interpolate=True)
         return fw80mc + self.approximate_idx - self.spacing
Exemplo n.º 2
0
 def find_mlc_peak(self, mlc_center):
     """Determine the center of the picket."""
     mlc_rows = np.arange(mlc_center - self.sample_width,
                          mlc_center + self.sample_width + 1)
     if self.settings.orientation == orientations['UD']:
         pix_vals = np.median(self.picket_array[mlc_rows, :], axis=0)
     else:
         pix_vals = np.median(self.picket_array[:, mlc_rows], axis=1)
     if max(pix_vals) > np.percentile(self.picket_array, 80):
         prof = SingleProfile(pix_vals)
         fw80mc = prof.fwxm_center(70, interpolate=True)
         return fw80mc + self.approximate_idx - self.spacing
Exemplo n.º 3
0
    def _determine_center(self, plane):
        """Automatically find the center of the field based on FWHM."""
        if not self._img_is_loaded:
            raise AttributeError("An image has not yet been loaded")

        self.image.check_inversion()
        self.image.ground()

        col_prof = np.median(self.image, 0)
        col_prof = SingleProfile(col_prof)
        row_prof = np.median(self.image, 1)
        row_prof = SingleProfile(row_prof)

        x_cen = col_prof.fwxm_center()
        y_cen = row_prof.fwxm_center()

        if _is_crossplane(plane):
            return y_cen
        elif _is_inplane(plane):
            return x_cen
        elif _is_both_planes(plane):
            return y_cen, x_cen
Exemplo n.º 4
0
def symmetry_point_difference(profile: SingleProfile):
    """Calculation of symmetry by way of point difference equidistant from the CAX"""
    values = profile.field_values(field_width=0.8)
    lt_edge, rt_edge = profile.field_edges(field_width=0.8)
    cax = profile.fwxm_center()
    dcax = profile.values[cax]
    max_val = 0
    sym_array = []
    for lt_pt, rt_pt in zip(values, values[::-1]):
        val = 100 * abs(lt_pt - rt_pt) / dcax
        sym_array.append(val)
        if val > max_val:
            max_val = val
    symmetry = max_val
    return symmetry, sym_array, lt_edge, rt_edge
Exemplo n.º 5
0
def flatsym_helper(args):
    calc_definition = args["calc_definition"]
    center_definition = args["center_definition"]
    center_x = args["center_x"]
    center_y = args["center_y"]
    invert = args["invert"]
    w = args["instance"]
    station = args["station"]
    imgdescription = args["imgdescription"]
    displayname = args["displayname"]
    acquisition_datetime = args["acquisition_datetime"]

    general_functions.set_configuration(
        args["config"])  # Transfer to this process

    # Collect data for "save results"
    dicomenergy = general_functions.get_energy_from_imgdescription(
        imgdescription)
    user_machine, user_energy = general_functions.get_user_machine_and_energy(
        station, dicomenergy)
    machines_and_energies = general_functions.get_machines_and_energies(
        general_functions.get_treatmentunits_flatsym())
    tolerances = general_functions.get_tolerance_user_machine_flatsym(
        user_machine)  # If user_machne has specific tolerance
    if not tolerances:
        tolerance_flat, tolerance_sym, pdf_report_enable = general_functions.get_settings_flatsym(
        )
    else:
        tolerance_flat, tolerance_sym, pdf_report_enable = tolerances[0]

    tolerance_flat = float(tolerance_flat)
    tolerance_sym = float(tolerance_sym)

    save_results = {
        "user_machine": user_machine,
        "user_energy": user_energy,
        "machines_and_energies": machines_and_energies,
        "displayname": displayname
    }

    temp_folder, file_path = RestToolbox.GetSingleDcm(config.ORTHANC_URL, w)

    try:
        flatsym = FlatSym(file_path)
    except Exception as e:
        return template("error_template", {
            "error_message":
            "The FlatSym module cannot calculate. " + str(e)
        })

    # Define the center pixel where to get profiles:
    def find_field_centroid(img):
        '''taken from pylinac WL module'''
        min, max = np.percentile(img.image.array, [5, 99.9])
        # min, max = np.amin(img.array), np.max(img.array)

        threshold_img = img.image.as_binary((max - min) / 2 + min)
        # clean single-pixel noise from outside field
        coords = ndimage.measurements.center_of_mass(threshold_img)
        return (int(coords[-1]), int(coords[0]))

    flatsym.image.crop(pixels=2)
    flatsym.image.check_inversion()
    if invert:
        flatsym.image.invert()
    flatsym.image.array = np.flipud(flatsym.image.array)
    vmax = flatsym.image.array.max()

    if center_definition == "Automatic":
        center_int = [
            int(flatsym.image.array.shape[1] / 2),
            int(flatsym.image.array.shape[0] / 2)
        ]
        center = [0.5, 0.5]
    elif center_definition == "CAX":
        center_int = find_field_centroid(
            flatsym)  # Define as mechanical isocenter
        center = [
            int(center_int[0]) / flatsym.image.array.shape[1],
            int(center_int[1]) / flatsym.image.array.shape[0]
        ]
    else:
        center_int = [int(center_x), int(center_y)]
        center = [
            int(center_x) / flatsym.image.array.shape[1],
            int(center_y) / flatsym.image.array.shape[0]
        ]

    fig = Figure(figsize=(9, 9), tight_layout={"w_pad": 1})
    ax = fig.add_subplot(1, 1, 1)
    ax.imshow(flatsym.image.array,
              cmap=matplotlib.cm.jet,
              interpolation="none",
              vmin=0.9 * vmax,
              vmax=vmax,
              aspect="equal",
              origin='lower')
    ax.autoscale(tight=True)

    # Plot lines along which the profiles are calculated:
    ax.plot([0, flatsym.image.array.shape[1]], [center_int[1], center_int[1]],
            "b-",
            linewidth=2)
    ax.plot([center_int[0], center_int[0]], [0, flatsym.image.array.shape[0]],
            c="darkgreen",
            linestyle="-",
            linewidth=2)
    ax.set_xlim([0, flatsym.image.array.shape[1]])
    ax.set_ylim([0, flatsym.image.array.shape[0]])

    # Get profiles
    crossplane = PylinacSingleProfile(flatsym.image.array[center_int[1], :])
    inplane = PylinacSingleProfile(flatsym.image.array[:, center_int[0]])

    # Do some filtering:
    crossplane.filter(kind='median', size=0.01)
    inplane.filter(kind='median', size=0.01)

    # Normalize profiles
    norm_val_crossplane = crossplane.values[center_int[0]]
    norm_val_inplane = inplane.values[center_int[1]]
    crossplane.normalize(norm_val=norm_val_crossplane)
    inplane.normalize(norm_val=norm_val_inplane)

    # Get index of CAX of both profiles(different than center) to be used for mirroring:
    fwhm_crossplane = crossplane.fwxm_center(interpolate=True)
    fwhm_inplane = inplane.fwxm_center(interpolate=True)

    # Plot profiles
    divider = make_axes_locatable(ax)

    ax_crossplane = divider.append_axes("bottom",
                                        size="40%",
                                        pad=0.25,
                                        sharex=ax)
    ax_crossplane.set_xlim([0, flatsym.image.array.shape[1]])
    ax_crossplane.set_xticks([])
    ax_crossplane.set_title("Crossplane")

    ax_inplane = divider.append_axes("right", size="40%", pad=0.25, sharey=ax)
    ax_inplane.set_ylim([0, flatsym.image.array.shape[0]])
    ax_inplane.set_yticks([])
    ax_inplane.set_title("Inplane")

    ax_crossplane.plot(crossplane._indices, crossplane, "b-")
    ax_crossplane.plot(2 * fwhm_crossplane - crossplane._indices, crossplane,
                       "b--")
    ax_inplane.plot(inplane, inplane._indices, c="darkgreen", linestyle="-")
    ax_inplane.plot(inplane,
                    2 * fwhm_inplane - inplane._indices,
                    c="darkgreen",
                    linestyle="--")

    ax_inplane.grid(alpha=0.5)
    ax_crossplane.grid(alpha=0.5)
    mpld3.plugins.connect(fig,
                          mpld3.plugins.MousePosition(fontsize=14, fmt=".2f"))

    script = mpld3.fig_to_html(fig, d3_url=D3_URL, mpld3_url=MPLD3_URL)

    if calc_definition == "Elekta":
        method = "elekta"
    else:
        method = "varian"

    try:
        flatsym.analyze(flatness_method=method,
                        symmetry_method=method,
                        vert_position=center[0],
                        horiz_position=center[1])
    except Exception as e:
        return template("error_template",
                        {"error_message": "Analysis failed. " + str(e)})

    symmetry_hor = round(flatsym.symmetry['horizontal']['value'], 2)
    symmetry_vrt = round(flatsym.symmetry['vertical']['value'], 2)
    flatness_hor = round(flatsym.flatness['horizontal']['value'], 2)
    flatness_vrt = round(flatsym.flatness['vertical']['value'], 2)
    horizontal_width = round(
        flatsym.symmetry['horizontal']['profile'].fwxm(interpolate=True) /
        flatsym.image.dpmm, 2)
    vertical_width = round(
        flatsym.symmetry['vertical']['profile'].fwxm(interpolate=True) /
        flatsym.image.dpmm, 2)
    horizontal_penumbra_width = round(
        flatsym.symmetry['horizontal']['profile'].penumbra_width(
            interpolate=True) / flatsym.image.dpmm, 2)
    vertical_penumbra_width = round(
        flatsym.symmetry['vertical']['profile'].penumbra_width(
            interpolate=True) / flatsym.image.dpmm, 2)

    # Check if passed
    if method == "varian":
        if (flatness_hor <
                tolerance_flat) and (flatness_vrt < tolerance_flat) and (
                    symmetry_hor < tolerance_sym) and (symmetry_vrt <
                                                       tolerance_sym):
            passed = True
        else:
            passed = False
    else:
        if (abs(flatness_hor - 100) < tolerance_flat) and (
                abs(flatness_vrt - 100) < tolerance_flat) and (
                    abs(symmetry_hor - 100) < tolerance_sym) and (
                        abs(symmetry_vrt - 100) < tolerance_sym):
            passed = True
        else:
            passed = False

    variables = {
        "symmetry_hor": symmetry_hor,
        "symmetry_vrt": symmetry_vrt,
        "flatness_hor": flatness_hor,
        "flatness_vrt": flatness_vrt,
        "horizontal_width": horizontal_width,
        "vertical_width": vertical_width,
        "horizontal_penumbra_width": horizontal_penumbra_width,
        "vertical_penumbra_width": vertical_penumbra_width,
        "passed": passed,
        "pdf_report_enable": pdf_report_enable,
        "script": script,
        "save_results": save_results,
        "acquisition_datetime": acquisition_datetime,
        "calc_definition": calc_definition
    }

    # Generate pylinac report:
    if pdf_report_enable == "True":
        pdf_file = tempfile.NamedTemporaryFile(delete=False,
                                               prefix="FlatSym",
                                               suffix=".pdf",
                                               dir=config.PDF_REPORT_FOLDER)
        flatsym.publish_pdf(pdf_file)
        variables["pdf_report_filename"] = os.path.basename(pdf_file.name)

    general_functions.delete_files_in_subfolders([temp_folder])  # Delete image

    return template("flatsym_results", variables)