Ejemplo n.º 1
0
    def get_centerline_optimized(self,
                                 alpha=1e3,
                                 beta=1e6,
                                 gamma=0.01,
                                 spacing=20,
                                 max_iterations=1000,
                                 endpoints=None):
        """ determines the center line of the polygon using an active contour
        algorithm """
        # use an active contour algorithm to find centerline
        ac = ActiveContour(blur_radius=1,
                           alpha=alpha,
                           beta=beta,
                           gamma=gamma,
                           closed_loop=False)
        ac.max_iterations = max_iterations

        # set the potential from the  distance map
        mask, offset = self.get_mask(1, ret_offset=True)
        potential = cv2.distanceTransform(mask, cv2.DIST_L2, 5)
        ac.set_potential(potential)

        # initialize the centerline from the estimate
        points = self.get_centerline_estimate(endpoints)
        points = curves.make_curve_equidistant(points, spacing=spacing)
        points = curves.translate_points(points, -offset[0], -offset[1])
        # anchor the end points
        anchor = np.zeros(len(points), np.bool)
        anchor[0] = anchor[-1] = True

        # find the best contour
        points = ac.find_contour(points, anchor, anchor)

        points = curves.make_curve_equidistant(points, spacing=spacing)
        return curves.translate_points(points, *offset)
Ejemplo n.º 2
0
    def get_centerline_optimized(self, alpha=1e3, beta=1e6, gamma=0.01,
                                 spacing=20, max_iterations=1000,
                                 endpoints=None):
        """ determines the center line of the polygon using an active contour
        algorithm """
        # use an active contour algorithm to find centerline
        ac = ActiveContour(blur_radius=1, alpha=alpha, beta=beta,
                           gamma=gamma, closed_loop=False)
        ac.max_iterations = max_iterations

        # set the potential from the  distance map
        mask, offset = self.get_mask(1, ret_offset=True)
        potential = cv2.distanceTransform(mask, cv2.DIST_L2, 5)
        ac.set_potential(potential)
        
        # initialize the centerline from the estimate
        points = self.get_centerline_estimate(endpoints)
        points = curves.make_curve_equidistant(points, spacing=spacing)        
        points = curves.translate_points(points, -offset[0], -offset[1])
        # anchor the end points
        anchor = np.zeros(len(points), np.bool)
        anchor[0] = anchor[-1] = True
        
        # find the best contour
        points = ac.find_contour(points, anchor, anchor)
        
        points = curves.make_curve_equidistant(points, spacing=spacing)        
        return curves.translate_points(points, *offset)
Ejemplo n.º 3
0
    def get_centerline_smoothed(self,
                                points=None,
                                spacing=10,
                                skip_length=90,
                                **kwargs):
        """ determines the center line of the polygon using an active contour
        algorithm. If `points` are given, they are used for getting the
        smoothed centerline. Otherwise, we determine the optimized centerline
        influenced by the additional keyword arguments.
        `skip_length` is the length that is skipped at either end of the center
            line when the smoothed variant is calculated
        """
        if points is None:
            points = self.get_centerline_optimized(spacing=spacing, **kwargs)

        length = curves.curve_length(points)

        # get the points to interpolate
        points = curves.make_curve_equidistant(points, spacing=spacing)
        skip_points = int(skip_length / spacing)
        points = points[skip_points:-skip_points]

        # do spline fitting to smooth the line
        smoothing_condition = length
        spline_degree = 3
        try:
            tck, _ = interpolate.splprep(np.transpose(points),
                                         k=spline_degree,
                                         s=smoothing_condition)
        except (ValueError, TypeError):
            # do not interpolate if there are problems
            pass
        else:
            # extend the center line in both directions to make sure that it
            # crosses the outline
            overshoot = 5 * skip_length  #< absolute overshoot
            num_points = (length + 2 * overshoot) / spacing
            overshoot /= length  #< overshoot relative to total length
            s = np.linspace(-overshoot, 1 + overshoot, num_points)
            points = interpolate.splev(s, tck)
            points = zip(*points)  #< transpose list

            # restrict center line to polygon shape
            cline = geometry.LineString(points).intersection(self.polygon)

            if isinstance(cline, geometry.MultiLineString):
                points = max(cline, key=lambda obj: obj.length).coords
            else:
                points = np.array(cline.coords)

        return points
Ejemplo n.º 4
0
 def get_centerline_smoothed(self, points=None, spacing=10, skip_length=90,
                             **kwargs):
     """ determines the center line of the polygon using an active contour
     algorithm. If `points` are given, they are used for getting the
     smoothed centerline. Otherwise, we determine the optimized centerline
     influenced by the additional keyword arguments.
     `skip_length` is the length that is skipped at either end of the center
         line when the smoothed variant is calculated
     """
     if points is None:
         points = self.get_centerline_optimized(spacing=spacing, **kwargs)
     
     # get properties of the line
     length = curves.curve_length(points)
     endpoints = points[0], points[-1]
     
     # get the points to interpolate
     points = curves.make_curve_equidistant(points, spacing=spacing)
     skip_points = int(skip_length / spacing)
     points = points[skip_points:-skip_points]
     
     # do spline fitting to smooth the line
     smoothing_condition = length
     spline_degree = 3
     try:
         tck, _ = interpolate.splprep(np.transpose(points), k=spline_degree,
                                      s=smoothing_condition)
     except (ValueError, TypeError):
         # do not interpolate if there are problems
         pass
     else:
         # extend the center line in both directions to make sure that it
         # crosses the outline
         overshoot = 20*skip_length #< absolute overshoot
         num_points = (length + 2*overshoot)/spacing
         overshoot /= length #< overshoot relative to total length
         s = np.linspace(-overshoot, 1 + overshoot, num_points)
         points = interpolate.splev(s, tck)
         points = zip(*points) #< transpose list
     
         # restrict center line to the section between the end points
         dists = spatial.distance.cdist(endpoints, points)
         ks = sorted(np.argmin(dists, axis=1))
         cline = geometry.LineString(points[ks[0] : ks[1]+1])
         
         if isinstance(cline, geometry.MultiLineString):
             points = max(cline, key=lambda obj: obj.length).coords
         else:
             points = np.array(cline.coords)
     
     return points
Ejemplo n.º 5
0
    def find_contour(self, curve, anchor_x=None, anchor_y=None):
        """ adapts the contour given by points to the potential image
        anchor_x can be a list of indices for those points whose x-coordinate
            should be kept fixed.
        anchor_y is the respective argument for the y-coordinate
        """
        if self.fx is None:
            raise RuntimeError('Potential must be set before the contour can '
                               'be adapted.')

        # curve must be equidistant for this implementation to work
        curve = np.asarray(curve)
        points = curves.make_curve_equidistant(curve)

        # check for marginal small cases
        if len(points) <= 2:
            return points

        def _get_anchors(indices, coord):
            """ helper function for determining the anchor points """
            if indices is None or len(indices) == 0:
                return tuple(), tuple()
            # get points where the coordinate `coord` has to be kept fixed
            ps = curve[indices, :]
            # find the points closest to the anchor points
            dist = spatial.distance.cdist(points, ps)
            return np.argmin(dist, axis=0), ps[:, coord]

        # determine anchor_points if requested
        if anchor_x is not None or anchor_y is not None:
            has_anchors = True
            x_idx, x_vals = _get_anchors(anchor_x, 0)
            y_idx, y_vals = _get_anchors(anchor_y, 1)
        else:
            has_anchors = False

        # determine point spacing if it is not given
        ds = curves.curve_length(points) / (len(points) - 1)

        # try loading the evolution matrix from the cache
        cache_key = (len(points), ds)
        Pinv = self._Pinv_cache.get(cache_key, None)
        if Pinv is None:
            # add new item to cache
            Pinv = self.get_evolution_matrix(len(points), ds)
            self._Pinv_cache[cache_key] = Pinv

        # restrict control points to shape of the potential
        points[:, 0] = np.clip(points[:, 0], 0, self.fx.shape[1] - 2)
        points[:, 1] = np.clip(points[:, 1], 0, self.fx.shape[0] - 2)

        # create intermediate array
        points_initial = points.copy()
        ps = points.copy()

        for k in xrange(self.max_iterations):
            # calculate external force
            fex = image.subpixels(self.fx, points)
            fey = image.subpixels(self.fy, points)

            # move control points
            ps[:, 0] = np.dot(Pinv, points[:, 0] + self.gamma * fex)
            ps[:, 1] = np.dot(Pinv, points[:, 1] + self.gamma * fey)

            # enforce the position of the anchor points
            if has_anchors:
                ps[x_idx, 0] = x_vals
                ps[y_idx, 1] = y_vals

            # check the distance that we evolved
            residual = np.abs(ps - points).sum()

            # restrict control points to shape of the potential
            points[:, 0] = np.clip(ps[:, 0], 0, self.fx.shape[1] - 2)
            points[:, 1] = np.clip(ps[:, 1], 0, self.fx.shape[0] - 2)

            if residual < self.residual_tolerance * self.gamma:
                break

        # collect additional information
        self.info['iteration_count'] = k + 1
        self.info['total_variation'] = np.abs(points_initial - points).sum()

        return points
Ejemplo n.º 6
0
    def find_contour(self, curve, anchor_x=None, anchor_y=None):
        """ adapts the contour given by points to the potential image
        anchor_x can be a list of indices for those points whose x-coordinate
            should be kept fixed.
        anchor_y is the respective argument for the y-coordinate
        """
        if self.fx is None:
            raise RuntimeError('Potential must be set before the contour can '
                               'be adapted.')

        # curve must be equidistant for this implementation to work
        curve = np.asarray(curve)    
        points = curves.make_curve_equidistant(curve)
        
        # check for marginal small cases
        if len(points) <= 2:
            return points
        
        def _get_anchors(indices, coord):
            """ helper function for determining the anchor points """
            if indices is None or len(indices) == 0:
                return tuple(), tuple()
            # get points where the coordinate `coord` has to be kept fixed
            ps = curve[indices, :] 
            # find the points closest to the anchor points
            dist = spatial.distance.cdist(points, ps)
            return np.argmin(dist, axis=0), ps[:, coord] 
        
        # determine anchor_points if requested
        if anchor_x is not None or anchor_y is not None:
            has_anchors = True
            x_idx, x_vals = _get_anchors(anchor_x, 0)
            y_idx, y_vals = _get_anchors(anchor_y, 1)
        else:
            has_anchors = False

        # determine point spacing if it is not given
        ds = curves.curve_length(points)/(len(points) - 1)
            
        # try loading the evolution matrix from the cache            
        cache_key = (len(points), ds)
        Pinv = self._Pinv_cache.get(cache_key, None)
        if Pinv is None:
            # add new item to cache
            Pinv = self.get_evolution_matrix(len(points), ds)
            self._Pinv_cache[cache_key] = Pinv
    
        # restrict control points to shape of the potential
        points[:, 0] = np.clip(points[:, 0], 0, self.fx.shape[1] - 2)
        points[:, 1] = np.clip(points[:, 1], 0, self.fx.shape[0] - 2)

        # create intermediate array
        points_initial = points.copy()
        ps = points.copy()
    
        for k in xrange(self.max_iterations):
            # calculate external force
            fex = image.subpixels(self.fx, points)
            fey = image.subpixels(self.fy, points)
            
            # move control points
            ps[:, 0] = np.dot(Pinv, points[:, 0] + self.gamma*fex)
            ps[:, 1] = np.dot(Pinv, points[:, 1] + self.gamma*fey)
            
            # enforce the position of the anchor points
            if has_anchors:
                ps[x_idx, 0] = x_vals
                ps[y_idx, 1] = y_vals
            
            # check the distance that we evolved
            residual = np.abs(ps - points).sum()

            # restrict control points to shape of the potential
            points[:, 0] = np.clip(ps[:, 0], 0, self.fx.shape[1] - 2)
            points[:, 1] = np.clip(ps[:, 1], 0, self.fx.shape[0] - 2)

            if residual < self.residual_tolerance * self.gamma:
                break
            
        # collect additional information
        self.info['iteration_count'] = k + 1
        self.info['total_variation'] = np.abs(points_initial - points).sum()
    
        return points