Example #1
0
 def get_total_length(self):
     """ return total length of all edges """
     for _, _, data in self.edges_iter(data=True):
         print curves.curve_length(data['curve'])
     return sum(
         curves.curve_length(data['curve'])
         for _, _, data in self.edges_iter(data=True))
    def simplify(self, epsilon=0):
        """ remove nodes with degree=2 and simplifies the curves describing the
        edges if epsilon is larger than 0 """
        # remove nodes with degree=2
        while True:
            for n, d in self.degree_iter():
                if d == 2:
                    try:
                        n1, n2 = self.neighbors(n)
                    except ValueError:
                        # this can happen for a self-loop, where n1 == n2
                        continue
                    
                    # get the points
                    points1 = self.get_single_edge_data(n, n1)['curve']
                    points2 = self.get_single_edge_data(n, n2)['curve']

                    # remove the node and the edges
                    self.remove_edges_from([(n, n1), (n, n2)])
                    self.remove_node(n)
                    
                    # add the new edge
                    points = curves.merge_curves(points1, points2)
                    self.add_edge_line(n1, n2, points)
                    break
            else:
                break #< no changes => we're done!
    
        # simplify the curves describing the edges
        if epsilon > 0:
            for _, _, data in self.edges_iter(data=True):
                data['curve'] = curves.simplify_curve(data['curve'], epsilon)
                data['length'] = curves.curve_length(data['curve'])
    def add_edge_line(self, n1, n2, curve):
        """ adds an edge to the graph """
        curve = np.asarray(curve)
        p1, p2 = curve[0], curve[-1]

        coords1, coords2 = self.node[n1]["coords"], self.node[n2]["coords"]

        if np.allclose(p1, coords1) and np.allclose(p2, coords2):
            data = {"curve": curve, "length": curves.curve_length(curve)}

        elif np.allclose(p1, coords2) and np.allclose(p2, coords1):
            data = {"curve": curve[::-1], "length": curves.curve_length(curve)}

        else:
            raise ValueError("The curve given by `curve` does not connect the " "specified nodes.")

        if data["length"] > 1e-6:
            self.add_edge(n1, n2, attr_dict=data)
Example #4
0
    def add_edge_line(self, n1, n2, curve):
        """ adds an edge to the graph """
        curve = np.asarray(curve)
        p1, p2 = curve[0], curve[-1]

        coords1, coords2 = self.node[n1]['coords'], self.node[n2]['coords']

        if (np.allclose(p1, coords1) and np.allclose(p2, coords2)):
            data = {'curve': curve, 'length': curves.curve_length(curve)}

        elif (np.allclose(p1, coords2) and np.allclose(p2, coords1)):
            data = {'curve': curve[::-1], 'length': curves.curve_length(curve)}

        else:
            raise ValueError('The curve given by `curve` does not connect the '
                             'specified nodes.')

        if data['length'] > 1e-6:
            self.add_edge(n1, n2, attr_dict=data)
    def add_edge_line(self, n1, n2, curve):
        """ adds an edge to the graph """
        curve = np.asarray(curve)
        p1, p2 = curve[0], curve[-1]
        
        coords1, coords2 = self.node[n1]['coords'], self.node[n2]['coords']
        
        if (np.allclose(p1, coords1) and np.allclose(p2, coords2)):
            data = {'curve': curve,
                    'length': curves.curve_length(curve)}
            
        elif (np.allclose(p1, coords2) and  np.allclose(p2, coords1)):
            data = {'curve': curve[::-1],
                    'length': curves.curve_length(curve)}
            
        else:
            raise ValueError('The curve given by `curve` does not connect the '
                             'specified nodes.')

        if data['length'] > 1e-6:
            self.add_edge(n1, n2, attr_dict=data)
Example #6
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
Example #7
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
 def get_total_length(self):
     """ return total length of all edges """
     for _, _, data in self.edges_iter(data=True):
         print curves.curve_length(data['curve'])
     return sum(curves.curve_length(data['curve'])
                for _, _, data in self.edges_iter(data=True))
Example #9
0
    def get_centerline_estimate(self, end_points=None):
        """ determines an estimate to a center line of the polygon
        `end_points` can either be None, a single Point, or two points.
        """
        import regions  #< lazy import to prevent circular dependencies

        def _find_point_connection(p1, p2=None, maximize_distance=False):
            """ estimate centerline between the one or two points """
            mask, offset = self.get_mask(margin=2,
                                         dtype=np.int32,
                                         ret_offset=True)

            p1 = (p1[0] - offset[0], p1[1] - offset[1])

            if maximize_distance or p2 is None:
                dist_prev = 0 if maximize_distance else np.inf
                # iterate until second point is found
                while True:
                    # make distance map starting from point p1
                    distance_map = mask.copy()
                    regions.make_distance_map(distance_map,
                                              start_points=(p1, ))
                    # find point farthest point away from p1
                    idx_max = np.unravel_index(distance_map.argmax(),
                                               distance_map.shape)
                    dist = distance_map[idx_max]
                    p2 = idx_max[1], idx_max[0]

                    if dist <= dist_prev:
                        break
                    dist_prev = dist
                    # take farthest point as new start point
                    p1 = p2
            else:
                # locate the centerline between the two given points
                p2 = (p2[0] - offset[0], p2[1] - offset[1])
                distance_map = mask
                regions.make_distance_map(distance_map,
                                          start_points=(p1, ),
                                          end_points=(p2, ))

            # find path between p1 and p2
            path = regions.shortest_path_in_distance_map(distance_map, p2)
            return curves.translate_points(path, *offset)

        if end_points is None:
            # determine both end points
            path = _find_point_connection(np.array(self.position),
                                          maximize_distance=True)
        else:
            end_points = np.squeeze(end_points)

            if end_points.shape == (2, ):
                # determine one end point
                path = _find_point_connection(end_points,
                                              maximize_distance=False)
            elif end_points.shape == (2, 2):
                # both end points are already determined
                path = _find_point_connection(end_points[0], end_points[1])

            elif end_points.ndim == 2 and end_points.shape[1] == 2:
                # multiple end points found => we have to find the end points
                # that are farthest apart
                longest_path, length = None, 0
                for k_1, p_1 in enumerate(end_points):
                    for p_2 in end_points[:k_1]:
                        path = _find_point_connection(p_1, p_2)
                        path_len = curves.curve_length(path)
                        if path_len > length:
                            longest_path, length = path, path_len

                path = longest_path

            else:
                raise TypeError('`end_points` must have shape (2,) or (n, 2), '
                                'but we found %s' % str(end_points.shape))

        return path
Example #10
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
    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
Example #12
0
    def get_centerline_estimate(self, end_points=None):
        """ determines an estimate to a center line of the polygon
        `end_points` can either be None, a single point, or two points.
        """
        import regions #< lazy import to prevent circular dependencies
        
        def _find_point_connection(p1, p2=None, maximize_distance=False):
            """ estimate centerline between the one or two points """
            mask, offset = self.get_mask(margin=2, dtype=np.int32,
                                         ret_offset=True)

            p1 = (p1[0] - offset[0], p1[1] - offset[1])

            if maximize_distance or p2 is None:
                dist_prev = 0 if maximize_distance else np.inf
                # iterate until second point is found
                while True:
                    # make distance map starting from point p1
                    distance_map = mask.copy()
                    regions.make_distance_map(distance_map, start_points=(p1,))
                    # find point farthest point away from p1
                    idx_max = np.unravel_index(distance_map.argmax(),
                                               distance_map.shape)
                    dist = distance_map[idx_max]
                    p2 = idx_max[1], idx_max[0]

                    if dist <= dist_prev:
                        break
                    dist_prev = dist
                    # take farthest point as new start point
                    p1 = p2
            else:
                # locate the centerline between the two given points
                p2 = (p2[0] - offset[0], p2[1] - offset[1])
                distance_map = mask
                regions.make_distance_map(distance_map,
                                          start_points=(p1,), end_points=(p2,))
                
            # find path between p1 and p2
            path = regions.shortest_path_in_distance_map(distance_map, p2)
            return curves.translate_points(path, *offset)
        
        
        if end_points is None:
            # determine both end points
            path = _find_point_connection(np.array(self.position),
                                          maximize_distance=True)
        else:
            end_points = np.squeeze(end_points)

            if end_points.shape == (2, ):
                # determine one end point
                path = _find_point_connection(end_points,
                                              maximize_distance=False)
            elif end_points.shape == (2, 2):
                # both end points are already determined
                path = _find_point_connection(end_points[0], end_points[1])
                
            elif end_points.ndim == 2 and end_points.shape[1] == 2:
                # multiple end points found => we have to find the end points
                # that are farthest apart
                longest_path, length = None, 0
                for k_1, p_1 in enumerate(end_points):
                    for p_2 in end_points[:k_1]:
                        path = _find_point_connection(p_1, p_2)
                        path_len = curves.curve_length(path)
                        if path_len > length:
                            longest_path, length = path, path_len
                        
                path = longest_path
                
            else:
                raise TypeError('`end_points` must have shape (2,) or (n, 2), '
                                'but we found %s' % str(end_points.shape))
            
        return path