def get_external_contour(points, resolution=None): """ takes a list of `points` defining a linear ring, which can be self-intersecting, and returns an approximation to the external contour """ if resolution is None: # determine resolution from minimal distance of consecutive points dist_min = np.inf for p1, p2 in itertools.izip(np.roll(points, 1, axis=0), points): dist = curves.point_distance(p1, p2) if dist > 0: dist_min = min(dist_min, dist) resolution = 0.5*dist_min # limit the resolution such that there are at most 2048 points dim_max = np.max(np.ptp(points, axis=0)) #< longest dimension resolution = max(resolution, dim_max/2048) # build a linear ring with integer coordinates ps_int = np.array(np.asarray(points)/resolution, np.int) ring = geometry.LinearRing(ps_int) # get the image of the linear ring by plotting it into a mask x_min, y_min, x_max, y_max = ring.bounds shape = ((y_max - y_min) + 3, (x_max - x_min) + 3) x_off, y_off = int(x_min - 1), int(y_min - 1) mask = np.zeros(shape, np.uint8) cv2.fillPoly(mask, [ps_int], 255, offset=(-x_off, -y_off)) # find the contour of this mask to recover the exterior contour contours = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE, offset=(x_off, y_off))[1] return np.array(np.squeeze(contours))*resolution
def get_external_contour(points, resolution=None): """ takes a list of `points` defining a linear ring, which can be self-intersecting, and returns an approximation to the external contour """ if resolution is None: # determine resolution from minimal distance of consecutive points dist_min = np.inf for p1, p2 in itertools.izip(np.roll(points, 1, axis=0), points): dist = curves.point_distance(p1, p2) if dist > 0: dist_min = min(dist_min, dist) resolution = 0.5 * dist_min # limit the resolution such that there are at most 2048 points dim_max = np.max(np.ptp(points, axis=0)) #< longest dimension resolution = max(resolution, dim_max / 2048) # build a linear ring with integer coordinates ps_int = np.array(np.asarray(points) / resolution, np.int) ring = geometry.LinearRing(ps_int) # get the image of the linear ring by plotting it into a mask x_min, y_min, x_max, y_max = ring.bounds shape = ((y_max - y_min) + 3, (x_max - x_min) + 3) x_off, y_off = int(x_min - 1), int(y_min - 1) mask = np.zeros(shape, np.uint8) cv2.fillPoly(mask, [ps_int], 255, offset=(-x_off, -y_off)) # find the contour of this mask to recover the exterior contour contours = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE, offset=(x_off, y_off))[1] return np.array(np.squeeze(contours)) * resolution
def get_ray_hitpoint(point_anchor, point_far, line_string, ret_dist=False): """ returns the point where a ray anchored at point_anchor hits the polygon given by line_string. The ray extends out to point_far, which should be a point beyond the polygon. If ret_dist is True, the distance to the hit point is also returned. """ # define the ray ray = geometry.LineString((point_anchor, point_far)) # find the intersections between the ray and the burrow contour try: inter = line_string.intersection(ray) except geos.TopologicalError: inter = None # process the result if isinstance(inter, geometry.Point): if ret_dist: # also return the distance dist = curves.point_distance(inter.coords[0], point_anchor) return inter.coords[0], dist else: return inter.coords[0] elif inter is not None and not inter.is_empty: # find closest intersection if there are many points dists = [ curves.point_distance(p.coords[0], point_anchor) for p in inter ] k_min = np.argmin(dists) if ret_dist: return inter[k_min].coords[0], dists[k_min] else: return inter[k_min].coords[0] else: # return empty result if ret_dist: return None, np.nan else: return None
def get_ray_hitpoint(point_anchor, point_far, line_string, ret_dist=False): """ returns the point where a ray anchored at point_anchor hits the polygon given by line_string. The ray extends out to point_far, which should be a point beyond the polygon. If ret_dist is True, the distance to the hit point is also returned. """ # define the ray ray = geometry.LineString((point_anchor, point_far)) # find the intersections between the ray and the burrow contour try: inter = line_string.intersection(ray) except geos.TopologicalError: inter = None # process the result if isinstance(inter, geometry.Point): if ret_dist: # also return the distance dist = curves.point_distance(inter.coords[0], point_anchor) return inter.coords[0], dist else: return inter.coords[0] elif inter is not None and not inter.is_empty: # find closest intersection if there are many points dists = [curves.point_distance(p.coords[0], point_anchor) for p in inter] k_min = np.argmin(dists) if ret_dist: return inter[k_min].coords[0], dists[k_min] else: return inter[k_min].coords[0] else: # return empty result if ret_dist: return None, np.nan else: return None
def get_closest_node(self, point): """ get the node that is closest to a given point. This function returns three values: * the id of the closest node * its coordinates * the distance of this node to the given point """ node_min, coord_min, dist_min = None, None, np.inf for node, data in self.nodes_iter(data=True): dist = curves.point_distance(point, data['coords']) if dist < dist_min: node_min, coord_min, dist_min = node, data['coords'], dist return node_min, coord_min, dist_min
def from_skeleton(cls, skeleton, copy=True, post_process=True): """ determines the morphological graph from the image `skeleton` `copy` determines whether the skeleton is copied before its modified `post_process` determines whether some post processing is performed that removes spurious edges and nodes """ if copy: skeleton = skeleton.copy() graph = cls() # count how many neighbors each point has kernel = np.ones((3, 3), np.uint8) kernel[1, 1] = 0 neighbors = cv2.filter2D(skeleton, -1, kernel) * skeleton # find an point with minimal neighbors to start iterating from neighbors_min = neighbors[neighbors > 0].min() ps = np.nonzero(neighbors == neighbors_min) start_point = (ps[1][0], ps[0][0]) # initialize graph by adding first node start_node = graph.add_node_point(start_point) edge_seeds = {start_point: start_node} # iterate over all edges while edge_seeds: # pick new point from edge_seeds and initialize the point list p, start_node = edge_seeds.popitem() points = [graph.node[start_node]['coords']] # iterate along the edge while True: # handle the current point points.append(p) skeleton[p[1], p[0]] = 0 # look at the neighborhood of the current point ps_n = skeleton[p[1]-1 : p[1]+2, p[0]-1 : p[0]+2] neighbor_count = ps_n.sum() #print neighbor_count if neighbor_count == 1: # find the next point along this edge dy, dx = np.nonzero(ps_n) p = (p[0] + dx[0] - 1, p[1] + dy[0] - 1) else: # the current point ends the edge break # check whether we are close to another edge seed for p_seed in edge_seeds: dist = curves.point_distance(p, p_seed) if dist < 1.5: # distance should be either 1 or sqrt(2) if dist > 0: points.append(p_seed) node = edge_seeds.pop(p_seed) points.append(graph.node[node]['coords']) break else: # could not find a close edge seed => this is an end point node = graph.add_node_point(p) # check whether we have to branch off other edges if neighbor_count > 0: assert neighbor_count > 1 # current points is a crossing => branch off new edge seeds # find all points from which we have to branch off dps = np.transpose(np.nonzero(ps_n)) # initialize all edge seeds seeds = set([(p[0] + dx - 1, p[1] + dy - 1) for dy, dx in dps]) while seeds: # check the neighbor hood of the seed point p_seed = seeds.pop() skeleton[p_seed[1], p_seed[0]] = 0 ps_n = skeleton[p_seed[1]-1 : p_seed[1]+2, p_seed[0]-1 : p_seed[0]+2] neighbor_count = ps_n.sum() #print 'test_seed', p_seed, neighbor_count if neighbor_count == 1: edge_seeds[p_seed] = node else: # add more seeds dps = np.transpose(np.nonzero(ps_n)) for dy, dx in dps: p = (p_seed[0] + dx - 1, p_seed[1] + dy - 1) if p not in seeds and p not in edge_seeds: seeds.add(p) # add the edge to the graph graph.add_edge_line(start_node, node, points) if post_process: # remove small edges and self-loops graph.remove_short_edges(4) # remove nodes of degree 2 graph.simplify() return graph
# Finding the max values of the contour i.e. the outline points of the mask. # if hierarchy[0][1] != []: c = cnts[0] #max(cnts , key = cv2.contourArea) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(img2, mask=thresh2) # Defining the most bottom extreme point of the mask bottom = tuple(c[c[:, :, 1].argmax()][0]) Botx.append(bottom[0]) Boty.append(bottom[1]) # Appending the most bottom point coordinates after each iteration and calculating the actual distance moved. # Also recording the passing frames to compare against time. Bottom_x.append(bottom[0]) Bottom_y.append(bottom[1]) bot_distance = 5 * 5.86 * point_distance( (Bottom_x[0], Bottom_y[0]), bottom) Bot_dist.append(bot_distance) Frame_count.append(i) #============================================================================== #============================================================================== #cv2.circle(gray,bottom,5,(255,255,255),-1) #============================================================================== #============================================================================== # Fitting an eclipse around the contour points or the mask. for c in cons: # Fitting only starts if there are 5 or more outline points as opencv requires this amount for fitting. Also # fitting starts only after the flash has passed.