コード例 #1
0
 def _calc_flatness(self, method: str, vert_position: float,
                    horiz_position: float):
     vert_profile = SingleProfile(
         self.image.
         array[:, int(round(self.image.array.shape[1] * vert_position))])
     horiz_profile = SingleProfile(self.image.array[
         int(round(self.image.array.shape[0] * horiz_position)), :])
     # calc flatness from profile
     flatness_calculation = FLATNESS_EQUATIONS[method.lower()]
     vert_flatness, vert_max, vert_min, vert_lt, vert_rt = flatness_calculation(
         vert_profile)
     horiz_flatness, horiz_max, horiz_min, horiz_lt, horiz_rt = flatness_calculation(
         horiz_profile)
     return {
         'method': method,
         'horizontal': {
             'value': horiz_flatness,
             'profile': horiz_profile,
             'profile max': horiz_max,
             'profile min': horiz_min,
             'profile left': horiz_lt,
             'profile right': horiz_rt,
         },
         'vertical': {
             'value': vert_flatness,
             'profile': vert_profile,
             'profile max': vert_max,
             'profile min': vert_min,
             'profile left': vert_lt,
             'profile right': vert_rt,
         },
     }
コード例 #2
0
    def _get_reasonable_start_point(self):
        """Set the algorithm starting point automatically.

        Notes
        -----
        The determination of an automatic start point is accomplished by finding the Full-Width-80%-Max.
        Finding the maximum pixel does not consistently work, esp. in the presence of a pin prick. The
        FW80M is a more consistent metric for finding a good start point.
        """
        # sum the image along each axis within the central 1/3 (avoids outlier influence from say, gantry shots)
        top_third = int(self.image.array.shape[0] / 3)
        bottom_third = int(top_third * 2)
        left_third = int(self.image.array.shape[1] / 3)
        right_third = int(left_third * 2)
        central_array = self.image.array[top_third:bottom_third,
                                         left_third:right_third]

        x_sum = np.sum(central_array, 0)
        y_sum = np.sum(central_array, 1)

        # Calculate Full-Width, 80% Maximum center
        fwxm_x_point = SingleProfile(x_sum).fwxm_center(80) + left_third
        fwxm_y_point = SingleProfile(y_sum).fwxm_center(80) + top_third
        center_point = Point(fwxm_x_point, fwxm_y_point)
        return center_point
コード例 #3
0
 def _calc_symmetry(self, method: str, vert_position: float,
                    horiz_position: float):
     vert_profile = SingleProfile(
         self.image.
         array[:, int(round(self.image.array.shape[1] * vert_position))])
     horiz_profile = SingleProfile(self.image.array[
         int(round(self.image.array.shape[0] * horiz_position)), :])
     # calc sym from profile
     symmetry_calculation = SYMMETRY_EQUATIONS[method.lower()]
     vert_sym, vert_sym_array, vert_lt, vert_rt = symmetry_calculation(
         vert_profile)
     horiz_sym, horiz_sym_array, horiz_lt, horiz_rt = symmetry_calculation(
         horiz_profile)
     return {
         'method': method,
         'horizontal': {
             'profile': horiz_profile,
             'value': horiz_sym,
             'array': horiz_sym_array,
             'profile left': horiz_lt,
             'profile right': horiz_rt,
         },
         'vertical': {
             'profile': vert_profile,
             'value': vert_sym,
             'array': vert_sym_array,
             'profile left': vert_lt,
             'profile right': vert_rt,
         },
     }
コード例 #4
0
    def test_interpolation(self):
        # centered field
        field = generate_open_field()
        # no interp
        p = SingleProfile(field.image[:, int(field.shape[1] / 2)], interpolation=Interpolation.NONE)
        self.assertEqual(len(p.values), len(field.image[:, int(field.shape[1] / 2)]))

        # linear interp
        p = SingleProfile(field.image[:, int(field.shape[1] / 2)], interpolation=Interpolation.LINEAR, interpolation_factor=10)
        self.assertEqual(len(p.values), len(field.image[:, int(field.shape[1] / 2)])*10)

        p = SingleProfile(field.image[:, int(field.shape[1] / 2)], interpolation=Interpolation.LINEAR,
                          dpmm=1/field.pixel_size, interpolation_resolution_mm=0.1)
        # right length
        self.assertEqual(len(p.values), len(field.image[:, int(field.shape[1] / 2)])*field.pixel_size/0.1)
        # right dpmm
        self.assertEqual(p.dpmm, 10)

        # spline interp
        p = SingleProfile(field.image[:, int(field.shape[1] / 2)], interpolation=Interpolation.SPLINE, interpolation_factor=10)
        self.assertEqual(len(p.values), len(field.image[:, int(field.shape[1] / 2)])*10)

        p = SingleProfile(field.image[:, int(field.shape[1] / 2)], interpolation=Interpolation.SPLINE,
                          dpmm=1/field.pixel_size, interpolation_resolution_mm=0.1)
        # right length
        self.assertEqual(len(p.values), len(field.image[:, int(field.shape[1] / 2)])*field.pixel_size/0.1)
        # right dpmm
        self.assertEqual(p.dpmm, 10)
コード例 #5
0
    def test_geometric_center(self):
        # centered field
        field = generate_open_field()
        p = SingleProfile(field.image[:, int(field.shape[1]/2)], interpolation=Interpolation.NONE)
        self.assertAlmostEqual(p.geometric_center()['index (exact)'], field.shape[0]/2, delta=1)

        # offset field should still be centered
        field = generate_open_field(center=(20, 20))
        p = SingleProfile(field.image[:, int(field.shape[1]/2)], interpolation=Interpolation.NONE)
        self.assertAlmostEqual(p.geometric_center()['index (exact)'], field.shape[0]/2, delta=1)
コード例 #6
0
    def test_beam_center(self):
        # centered field
        field = generate_open_field()
        p = SingleProfile(field.image[:, int(field.shape[1]/2)], interpolation=Interpolation.NONE)
        self.assertAlmostEqual(p.beam_center()['index (exact)'], field.shape[0]/2, delta=1)

        # offset field
        field = generate_open_field(center=(10, 10))
        p = SingleProfile(field.image[:, int(field.shape[1]/2)], interpolation=Interpolation.NONE)
        self.assertAlmostEqual(p.beam_center()['index (exact)'], 422, delta=1)
コード例 #7
0
    def _find_bb(self):
        """Find the BB within the radiation field. Iteratively searches for a circle-like object
        by lowering a low-pass threshold value until found.

        Returns
        -------
        Point
            The weighted-pixel value location of the BB.
        """

        def is_boxlike(array):
            """Whether the binary object's dimensions are symmetric, i.e. box-like"""
            ymin, ymax, xmin, xmax = get_bounding_box(array)
            y = abs(ymax - ymin)
            x = abs(xmax - xmin)
            if x > max(y * 1.05, y+3) or x < min(y * 0.95, y-3):
                return False
            return True

        # get initial starting conditions
        hmin = np.percentile(self.array, 5)
        hmax = self.array.max()
        spread = hmax - hmin
        max_thresh = hmax

        # search for the BB by iteratively lowering the low-pass threshold value until the BB is found.
        found = False
        while not found:
            try:
                lower_thresh = hmax - spread / 2
                t = np.where((max_thresh > self) & (self >= lower_thresh), 1, 0)
                labeled_arr, num_roi = ndimage.measurements.label(t)
                roi_sizes, bin_edges = np.histogram(labeled_arr, bins=num_roi + 1)
                bw_node_cleaned = np.where(labeled_arr == np.argsort(roi_sizes)[-3], 1, 0)
                expected_fill_ratio = np.pi / 4
                actual_fill_ratio = get_filled_area_ratio(bw_node_cleaned)
                if (expected_fill_ratio * 1.1 < actual_fill_ratio) or (actual_fill_ratio < expected_fill_ratio * 0.9):
                    raise ValueError
                if not is_boxlike(bw_node_cleaned):
                    raise ValueError
            except (IndexError, ValueError):
                max_thresh -= 0.05 * spread
                if max_thresh < hmin:
                    raise ValueError("Unable to locate the BB")
            else:
                found = True

        # determine the center of mass of the BB
        inv_img = Image.load(self.array)
        inv_img.invert()
        x_arr = np.abs(np.average(bw_node_cleaned, weights=inv_img, axis=0))
        x_com = SingleProfile(x_arr).fwxm_center(interpolate=True)
        y_arr = np.abs(np.average(bw_node_cleaned, weights=inv_img, axis=1))
        y_com = SingleProfile(y_arr).fwxm_center(interpolate=True)
        return Point(x_com, y_com)
コード例 #8
0
ファイル: BWHIsoCube.py プロジェクト: clmw83/pylinac-bwhdfci
    def find_bb(self):
        """Find the BB within the radiation field. Dervived from pylinac WL test.  Looks at the central 60x60 pixels and finds
        a bb

        Returns
        -------
        Point
            The weighted-pixel value location of the BB.
        """
        span=20
        bbox=[int(self.cax.y-span),int(self.cax.x-span),int(self.cax.y+span),int(self.cax.x+span)]
        subim=ndimage.gaussian_filter(np.array(self.array[bbox[0]:bbox[2],bbox[1]:bbox[3]],dtype=np.float),sigma=(1,1),order=0)

        self._bbox_max=np.max(subim)
        self._bbox_min=np.min(subim)
        
        hmin, hmax = np.percentile(subim, [10, 100.0])
        spread = hmax - hmin
        max_thresh = hmax
        lower_thresh = hmax - spread*.2
        # search for the BB by iteratively lowering the low-pass threshold value until the BB is found.
        found = False
        while not found:
            try:
                binary_arr = np.logical_and((subim <= max_thresh), (subim >= lower_thresh))
                labeled_arr, num_roi = ndimage.measurements.label(binary_arr)
                roi_sizes, bin_edges = np.histogram(labeled_arr, bins=num_roi + 1)
                bw_bb_img = np.where(labeled_arr == np.argsort(roi_sizes)[-2], 1, 0)
                if not self._is_round(bw_bb_img):
                    raise ValueError
                if not self._is_modest_size(bw_bb_img,subim.shape):
                    raise ValueError
                if not self._is_symmetric(bw_bb_img):
                    raise ValueError
            except (IndexError, ValueError):
                lower_thresh -= 0.05 * spread
                if lower_thresh < hmin:
                    raise ValueError("Unable to locate the BB. Make sure the field edges do not obscure the BB and that there is no artifact in the images.")
            else:
                found = True

        # determine the center of mass of the BB
        
        x_arr = np.abs(np.average(subim*bw_bb_img, axis=0))
        #plt.figure()
        #plt.plot(x_arr)
        #plt.figure()
        #plt.imshow(bw_bb_img)
        x_com = SingleProfile(np.array(x_arr,dtype=np.float)).fwxm_center(interpolate=True)
        y_arr = np.abs(np.average(subim*bw_bb_img, axis=1))
        y_com = SingleProfile(y_arr).fwxm_center(interpolate=True)              
        self.bb=Point(x_com+bbox[1], y_com+bbox[0])
コード例 #9
0
ファイル: vmat.py プロジェクト: carlosqueiroz/pylinac
    def median_profiles(self):
        """Return two median profiles from the open and dmlc image. For visual comparison."""
        # dmlc median profile
        dmlc_prof = SingleProfile(np.median(self.image_dmlc, axis=0))
        dmlc_prof.stretch()
        # open median profile
        open_prof = SingleProfile(np.median(self.image_open, axis=0))
        open_prof.stretch()

        # normalize the profiles to near the same value
        norm_val = np.percentile(dmlc_prof.values, 90)
        dmlc_prof.normalize(norm_val)
        norm_val = np.percentile(open_prof.values, 90)
        open_prof.normalize(norm_val)

        return dmlc_prof, open_prof
コード例 #10
0
 def _determine_measured_gap(profile: np.ndarray) -> float:
     """Return the measured gap based on profile height"""
     mid_value = profile[int(len(profile) / 2)]
     prof = SingleProfile(profile, normalization_method=Normalization.NONE)
     if mid_value < profile.mean():
         prof.invert()
     _, props = find_peaks(prof.values, max_number=1)
     if mid_value < profile.mean():
         return -props['prominences'][0]
     else:
         return props['prominences'][0]
コード例 #11
0
ファイル: picketfence.py プロジェクト: carlosqueiroz/pylinac
 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
コード例 #12
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
コード例 #13
0
    def _get_profile(self, plane, position):
        """Get a profile at the given position along the specified plane."""
        if not self._img_is_loaded:
            raise AttributeError("An image has not yet been loaded")

        position = self._convert_position(position, plane)

        # if position == 'auto':
        #     y, x = self._determine_center()
        # else:
        #     if _is_crossplane(plane):
        #         self._check_position_inbounds(position, plane)
        #         y = position
        #     elif _is_inplane(plane):
        #         self._check_position_inbounds(position, plane)
        #         x = position

        if _is_crossplane(plane):
            prof = SingleProfile(self.image[position[0], :])
        elif _is_inplane(plane):
            prof = SingleProfile(self.image[:, position[0]])
        return prof
コード例 #14
0
    def test_normalization(self):
        array = np.random.rand(1, 100).squeeze()

        # don't apply normalization
        max_v = array.max()
        p = SingleProfile(array, normalization_method=Normalization.NONE, interpolation=Interpolation.NONE, ground=False)
        self.assertEqual(max_v, p.values.max())

        # apply max norm
        p = SingleProfile(array, normalization_method=Normalization.MAX, interpolation=Interpolation.NONE)
        self.assertEqual(1.0, p.values.max())

        # make sure interpolation doesn't affect the norm
        p = SingleProfile(array, normalization_method=Normalization.MAX, interpolation=Interpolation.LINEAR)
        self.assertEqual(1.0, p.values.max())

        # test out a real field
        field = generate_open_field()
        p = SingleProfile(field.image[:, 500], normalization_method=Normalization.MAX)
        self.assertEqual(1.0, p.values.max())

        # filtered beam center is less than max value
        p = SingleProfile(field.image[:, 500], normalization_method=Normalization.BEAM_CENTER)
        self.assertGreaterEqual(p.values.max(), 1.0)
コード例 #15
0
    def to_profiles(
        self,
        n_detectors_row: int = 63,
        **kwargs
    ) -> Tuple[SingleProfile, SingleProfile, SingleProfile, SingleProfile]:
        """Convert the SNC data to SingleProfiles. These can be analyzed directly or passed to other modules like flat/sym.

        Parameters
        ----------
        n_detectors_row : int
            The number of detectors in a given row. Note that they Y profile includes 2 extra detectors from the other 3.
        """
        x_prof = SingleProfile(self.integrated_dose[:n_detectors_row],
                               **kwargs)
        y_prof = SingleProfile(
            self.integrated_dose[n_detectors_row:2 * n_detectors_row + 2],
            **kwargs)
        pos_prof = SingleProfile(
            self.integrated_dose[2 * n_detectors_row + 2:3 * n_detectors_row +
                                 2], **kwargs)
        neg_prof = SingleProfile(
            self.integrated_dose[3 * n_detectors_row + 2:4 * n_detectors_row +
                                 2], **kwargs)
        return x_prof, y_prof, pos_prof, neg_prof
コード例 #16
0
ファイル: test_profile.py プロジェクト: jdschmitt11/pylinac
 def setUpClass(cls):
     cls.profile = SingleProfile(cls.ydata, normalize_sides=cls.normalize_sides)