def getGraph(img,basename): img = binariseImage(img) / 255 ske = skeletonize(img).astype(np.uint16) # ske = img.astype('uint16') # build graph from skeleton graph = sknw.build_sknw(ske) # draw edges by pts for (s,e) in graph.edges(): ps = graph[s][e]['pts'] # draw node by o nodes = graph.nodes() ps = np.array([nodes[i]['o'] for i in nodes]) # print('EDGES',graph.edges()) # print('NODES',graph.nodes()) open('%s_edges.dat' % basename,'w').write(str(graph.edges())) open('%s_nodes.dat' % basename,'w').write(str(graph.nodes())) edges = np.array(graph.edges()) return edges, nodes
def graph_build(): name = "Cables" thresh = 127 threshold(name + ".jpg", thresh) img = img_as_bool( color.rgb2gray(io.imread("Cables_threshold_{}.jpg".format(thresh)))) ske = skeletonize(~img).astype(np.uint16) # build graph from skeleton graph = sknw.build_sknw(ske) # draw image plt.imshow(img, cmap='gray') manager = plt.get_current_fig_manager() manager.resize(*manager.window.maxsize()) # draw edges by pts for (s, e) in graph.edges(): ps = graph[s][e]['pts'] plt.plot(ps[:, 1], ps[:, 0], 'green') # draw node by o nodes = graph.nodes() ps = np.array([nodes[i]['o'] for i in nodes]) plt.plot(ps[:, 1], ps[:, 0], 'r.') # title and show plt.title('') plt.axis('off') plt.show()
def find_bridges_between_VLs(img, points, centerOfVLs, result=[], numOfBridges=0): src, des = points graph = sknw.build_sknw(img) # forkPoints = find_nodes(img) # show_img(img) try: # print("Finding the path...") path = nx.astar_path(graph, src, des)[1:-1] coordinates = np.array([ coor for p in path for coor in get_node_coordinate(graph, p) ]).tolist() forkPoints = np.array(find_nodes(img)).tolist() forkPoints = [p[::-1] for p in forkPoints] voronoi_points = [ coors for coors in coordinates if coors in forkPoints ] # print(voronoi_points) result.append(voronoi_points) for row, col in coordinates: img[row][col] = 0 debug = convert_binary_to_normal_im(img) # cv2.imwrite("removed_nodes_{}.png".format(numOfBridges), debug) except: # print("Result: ", result) return result numOfBridges += 1 return find_bridges_between_VLs(img, [src, des], centerOfVLs, result, numOfBridges)
def process_masks(mask_paths): lnstr_df = pd.DataFrame() with tqdm(total=len(mask_paths)) as pbar: for msk_pth in mask_paths: #print(msk_pth) msk = imread(msk_pth) msk = msk[6:1306, 6:1306] msk_nme = msk_pth.split('/')[-1] img_id = msk_nme[msk_nme.find('AOI'):msk_nme.find('.')] # open and skeletonize thresh = 30 binary = (msk > thresh) * 1 ske = skeletonize(binary).astype(np.uint16) # build graph from skeleton graph = sknw.build_sknw(ske, multi=True) segments = simplify_graph(graph) linestrings = segmets_to_linestrings(segments) local = pd.DataFrame() local['WKT_Pix'] = linestrings local['ImageId'] = img_id lnstr_df = pd.concat([lnstr_df, local], ignore_index=True) pbar.update(1) return lnstr_df
def generate_characteristic_array(): result_array = [] file_path_array = eachFile('/Users/zkx/PycharmProjects/GraphProject/Base/') for path_str in file_path_array: result_array_without_type = [] path_split = path_str.split('/') if path_str != '/Users/zkx/PycharmProjects/GraphProject/Base/.DS_Store': img = cv2.imread(path_str, 0) pic = cv2.resize(img, (300, 300), interpolation=cv2.INTER_CUBIC) image = transfer_matrix(pic) skeleton = skeletonize(image).astype(np.uint16) graph = sknw.build_sknw(skeleton, multi=False) draw_edges(graph) draw_nodes(graph) charac_object = generate_characteristic_set(graph) result_array_without_type.append(charac_object.num_node) result_array_without_type.append(charac_object.num_edge) result_array_without_type.append(charac_object.degree_1) result_array_without_type.append(charac_object.degree_2) charac_object.type = (path_split[len(path_split) - 1]).split('_')[0] result_array_without_type.append(int(charac_object.type)) result_array.append(result_array_without_type) #show_graph(image) result_array.sort(key=lambda x: x[4]) #print(result_array) return result_array
def find_bridges_between_VLs(img, points, centerOfVLs, result=[], numOfBridges=0): src, des = points graph = sknw.build_sknw(img) forkPoints = findingNodes(img) try: path = nx.astar_path(graph, src, des)[1:-1] coordinates = np.array([ coor for p in path for coor in get_node_coordinate(graph, p) ]).tolist() forkPoints = np.array(findingNodes(segment_skeleton)).tolist() forkPoints = [p[::-1] for p in forkPoints] voronoi_points = [ coors for coors in coordinates if coors in forkPoints ] result.append(voronoi_points) circle_image(img, coordinates, "bridge", numOfBridges) # print(voronoi_points) for row, col in coordinates: img[row][col] = 0 debug = convert_binary_to_normal_im(img) cv2.imwrite(cwd + "/debug/debug.png", debug) except: return result numOfBridges += 1
def skel2graph(skel): """ @brief Convert the pixel-wide skeleton into a networkx graph. @returns a ToolGraph representing the skeleton provided as input. """ return endotip.graph.ToolGraph().from_sknw(sknw.build_sknw(skel))
def calculateNavigationGraph(self, resolution=0.1, level=0, safetyMarginEdges=0.1, algorithm='medial-axis', shortLeafEdgesThresh=0.5, squishedLeafNodesThresh=0.15, redundantNodesThresh=0.25, longEdgesThreshold=0.5, doRemoveInaccessibleNodes=True, zlim=(0.15, 1.50), isBoundedByFloorMap=True, roomIds=None): occupancyMap, xlim, ylim = self.calculateOccupancyMap( resolution, level, zlim, isBoundedByFloorMap, roomIds) if algorithm == 'medial-axis': skeletonMap = medial_axis(occupancyMap) elif algorithm == 'skeleton': skeletonMap = skeletonize(occupancyMap) else: raise Exception('Unsupported algorithm: %s' % (algorithm)) distOccupancyMap = ndimage.distance_transform_edt(occupancyMap) factorX = occupancyMap.shape[0] / \ (xlim[1] - xlim[0]) # pixel per meter factorY = occupancyMap.shape[1] / \ (ylim[1] - ylim[0]) # pixel per meter assert np.allclose(factorX, factorY, atol=1e-6) nbSafetyPixels = int(safetyMarginEdges * factorX) skeletonMap[distOccupancyMap < nbSafetyPixels] = 0.0 graph = sknw.build_sknw(skeletonMap) graph = getLargestGraphOnly(graph) # FIXME: should probably run a loop here for several iterations graph = removeSelfEdges(graph) graph = removeShortLeafEdges(graph, threshold=shortLeafEdgesThresh * factorX) graph = removeSquishedLeafNodes(graph, distOccupancyMap, threshold=squishedLeafNodesThresh * factorX) graph = subdiviseLongEdges(graph, threshold=longEdgesThreshold * factorX) graph = removeRedundantNodes(graph, threshold=redundantNodesThresh * factorX) if doRemoveInaccessibleNodes: graph = removeInaccessibleNodes(graph, occupancyMap) graph = getLargestGraphOnly(graph) graph = NavigationGraph.fromNx(graph, factorX, xlim, ylim) return graph, occupancyMap, xlim, ylim
def skeleton(img1): start = time.time() ske = skeletonize(img1).astype(np.uint16) # build graph from skeleton graph = sknw.build_sknw(ske) # print('skeleton : ', time.time()-start) # draw image plt.imshow(img1, cmap='gray') return graph
def fine_segmentation(image): # Step 1: Thin each oversized segment size = get_img_shape(image) AveWid = size[1] * 0.8 segment_skeleton = morphology.skeletonize(image).astype(np.uint16) # show_img(segment_skeleton, "Skeleton") # Step 2: Draw vertical lines (VLs) h, w = shape = np.shape(segment_skeleton) # kernel = np.ones((8,1), np.uint8) # closingImg = cv2.morphologyEx(img_as_uint(segment_skeleton), cv2.MORPH_CLOSE, kernel) projection = [sum(segment_skeleton[:, i]) for i in range(w)] # plt.plot(projection) # plt.show() nMaximumPeaks = np.sort(projection)[w - int(np.ceil(w / AveWid)):w] maximumPeakPos = list(set([projection.index(i) for i in nMaximumPeaks])) for point in maximumPeakPos: segment_skeleton[:, point] = 1 segment_skeleton[int(h / 2), point + 1] = 1 segment_skeleton[int(h / 2), point - 1] = 1 # show_img(segment_skeleton,"Skeleton with VLs") # Step 3: Seek and seperate the shortest bridges between every VL pair graph = sknw.build_sknw(segment_skeleton) node, nodes = graph.node, graph.nodes() coordinates = [get_node_coordinate(graph, n) for n in nodes] centerOfVLs = [[int(h / 2), p] for p in maximumPeakPos] nodesOfVLs = [] for point in centerOfVLs: for index in range(len(coordinates)): if (point in coordinates[index].tolist()): nodesOfVLs.append(index) print("Center of VLs: ", np.sort(nodesOfVLs)) # draw_point(segment_skeleton, [get_node_coordinate(graph,n) for n in [27]]) vorPoints = find_bridges_between_VLs(segment_skeleton.copy(), [27, 28], centerOfVLs) print(vorPoints) # if (len(vorPoints[0])<4): # vorPoints[0].append(vorPoints[1][0]) combinations = vorPoints try: combinations[0].append(combinations[1][0]) except: pass print(combinations[0]) # Step 4: Seperated by Voronoi diagrams # seperating_points = [voronoi.voronoi_edges(setPoints) for setPoints in combinations] seperating_points = voronoi.voronoi_edges(combinations[0]) print(seperating_points) return seperating_points
def skeleton(img, save_filepath=None): (height, width) = img.shape[:2] img = img // 255 ske = skeletonize(img).astype(np.uint16) result = np.zeros((height, width), np.uint8) # build graph from skeleton graph = sknw.build_sknw(ske, multi=False) sknw.draw_graph(result, graph) result[result > 0] = 255 save_image(result, save_filepath) return result
def mask_to_line_strings(mask: np.ndarray, sigma: float = 0.5, threshold: float = 0.3, small_obj_size: int = 300, dilation: int = 1): mask = prepare_mask(mask=mask, sigma=sigma, threshold=threshold, small_obj_size=small_obj_size, dilation=dilation) ske = np.array(skeletonize(mask), dtype="uint8") ske = ske[8:-8, 8:-8] graph = sknw.build_sknw(ske, multi=True) all_coords = prepare_graph_edges(graph) line_strings = get_line_strings_from_coords(all_coords) return line_strings
def segmentize_slow(self, binarized, min_len=0): ske = skeletonize(binarized > 0).astype(numpy.uint8) segments = [[]] graph = sknw.build_sknw(ske) for (s, e) in graph.edges(): ps = graph[s][e]['pts'] xx = ps[:, 1] yy = ps[:, 0] if self.line_length(xx[0], yy[0], xx[-1], yy[-1]) > min_len: segment = [] for i in range(len(xx) - 1): segment.append((xx[i], yy[i])) #skeleton = cv2.line(skeleton, (xx[i], yy[i]), (xx[i + 1], yy[i + 1]), 255, thickness=1) segments.append(segment) segments = [numpy.array(s) for s in segments] return segments
def make_graph(skel, image, org): graph = sknw.build_sknw(skel, multi=False) gr_sensitivity = 15 gr_lb = np.array([60 - gr_sensitivity, 100, 50]) gr_ub = np.array([60 + gr_sensitivity, 255, 255]) rd_sensitivity = 15 rd_lb = np.array([0 - rd_sensitivity, 50, 50]) rd_ub = np.array([10 + rd_sensitivity, 255, 255]) gr = color_coordinate(org, gr_lb, gr_ub) rd = color_coordinate(org, rd_lb, rd_ub) #print(gr, " ", rd) add_node_to_graph(graph, [gr[1], gr[0]]) add_node_to_graph(graph, [rd[1], rd[0]]) add_edge_to_graph(graph, [gr[1], gr[0]], 2) add_edge_to_graph(graph, [rd[1], rd[0]], 1) return graph
def generate_request_charac_array(file_path): img = cv2.imread(file_path, 0) pic = cv2.resize(img, (300, 300), interpolation=cv2.INTER_CUBIC) image = transfer_matrix(pic) skeleton = skeletonize(image).astype(np.uint16) graph = sknw.build_sknw(skeleton, multi=False) draw_edges(graph) draw_nodes(graph) charac_object = generate_characteristic_set(graph) req_result_array = [] req_result_array.append(charac_object.num_node) req_result_array.append(charac_object.num_edge) req_result_array.append(charac_object.degree_1) req_result_array.append(charac_object.degree_2) #print(req_result_array) return req_result_array
def GetGraphFromImage(self, imageFileName): # open and skeletonize filePath = Closing2Folder + imageFileName; img24bit = imread(filePath) img = np.array(Image.fromarray(img24bit).quantize(colors=2, method=2)) # self.Show(img) binary = img > filters.threshold_otsu(img,100) #self.Show(img); self.binaryImg = binary ske = skeletonize(binary).astype(np.uint16) #self.ShowSkeleton(img,ske) self.SaveSkeleton(img, ske, imageFileName) # build graph from skeleton graph = sknw.build_sknw(ske) return graph
def extract_centerlines_sknw(edges): skel = skeletonize(256 - edges > 128) skg = sknw.build_sknw(skel.astype(np.uint16), multi=False, iso=True, ring=False) lines = [] for (s, e) in skg.edges(): ps = skg[s][e]['pts'] lines.append( geom.LineString(ps[:, ::-1] * np.array([1, -1]) + np.array([0, 256]))) # prune lines too long/short lines = [ line for line in lines if max(line.length, geom.Point(line.coords[0]).distance(geom.Point( line.coords[-1]))) > 4 ] return lines
def vectorize(blob): (skel, dist), path = blob logger.info(f"Vectorizing {path}...") graph = sknw.build_sknw(skel) df = gpd.GeoDataFrame(columns=['geometry', 'width']) ul, lr = get_geotiff_bbox(path) dy = ul[0] - lr[0] dx = lr[1] - ul[1] for s, e in graph.edges(): H, W = dist.shape widths = [dist[tuple(pt)] for pt in graph[s][e]['pts']] width = np.percentile(widths, 33) / H * dy N = len(graph[s][e]['pts']) + 2 pts = np.zeros((N, 2), dtype=np.float64) pts[0] = graph.node[s]['o'] pts[-1] = graph.node[e]['o'] pts[1:-1] = graph[s][e]['pts'] pts[:, 0] = 1 - pts[:, 0] / H pts[:, 0] *= dy pts[:, 0] += lr[0] pts[:, 1] = pts[:, 1] / W pts[:, 1] *= dx pts[:, 1] += ul[1] df = df.append({ 'geometry': LineString(pts[:, ::-1]), 'width': width }, ignore_index=True) return df
def extract_centerlines_shapes_sknw(edges): shapes = vector_trace(edges) img = np.zeros((256, 256), dtype=np.uint8) shapes = (shape.buffer(0) for shape in shapes) polys = [ poly for poly in shapes if type(poly) == geom.Polygon and type(poly.envelope) == geom.Polygon ] as_contour = [ np.array(poly.exterior.coords).astype(np.int32) for poly in polys ] as_contour = [c[:, np.newaxis, :] for c in as_contour] cv2.drawContours(img, as_contour, -1, 255, -1) skel = skeletonize(img > 128) skg = sknw.build_sknw(skel.astype(np.uint16), multi=False, iso=True, ring=False) lines = [] for (s, e) in skg.edges(): ps = skg[s][e]['pts'] lines.append(geom.LineString(ps[:, ::-1])) # prune lines too long/short lines = [ line for line in lines if max(line.length, geom.Point(line.coords[0]).distance(geom.Point( line.coords[-1]))) > 4 ] return lines
def nodes(mask): """ Inputs mask -- thresholded query image Outputs new_node_centers -- coordinates of each branching point, which is the center of each roi """ # Skeletonize tree and build graph network skeleton = skeletonize(mask // 255).astype(np.uint16) graph = sknw.build_sknw(skeleton) nodes = graph.nodes() node_centers = np.array([nodes[i]['o'] for i in nodes]) # Filter out nodes at tips of branches, keeping only nodes that define the centers of each ROI copy = graph.copy() for i in range(len(node_centers)): conn = [n for n in graph.neighbors(i)] if len(conn) < 3: copy.remove_node(i) new_nodes = copy.nodes() new_node_centers = np.array([new_nodes[i]['o'] for i in new_nodes]).astype(int) return new_node_centers
# load the image, convert it to grayscale, blur it slightly, # and threshold it image = cv2.imread('moment.jpg') image = image[167:972, 0:1920] gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (5, 5), 0) thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)[1] #image = thresh #roi = thresh[167:972, 0:1920] roi = cv2.bitwise_not(thresh) #cv2.rectangle(image,(0,166),(1920,972),(0,255,0),1) skeleton = skeletonize_3d(roi) graph = sknw.build_sknw(skeleton) plt.imshow(image, cmap='gray') for (s, e) in graph.edges(): ps = graph[s][e]['pts'] plt.plot(ps[:, 1], ps[:, 0], 'green') # draw node by o node, nodes = graph.node, graph.nodes() ps = np.array([node[i]['o'] for i in nodes]) plt.plot(ps[:, 1], ps[:, 0], 'r.') # title and show plt.title('Build Graph') plt.show()
def extract_graphs(sillh_skel): G = sknw.build_sknw(sillh_skel[1]) G.remove_nodes_from(list(nx.isolates(G))) return (sillh_skel[0], sillh_skel[1], G)
img = cv2.imread("img_eroded.png") kernel = np.ones((1, 1), np.uint8) #Convert to GrayScaledImage grayscaled = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) retval, threshold = cv2.threshold(grayscaled, 10, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) retval, threshold2 = cv2.threshold(threshold, 10, 255, cv2.THRESH_BINARY_INV) threshold2[threshold2 == 255] = 1 #Skeletonize the Thresholded Image skel = skeletonize(threshold2) #Build Graph from skeleton graph = sknw.build_sknw(skel, multi=False) G = nx.Graph(graph) #plt.imshow(img, cmap='gray') plt.axis('off') #for (s,e) in graph.edges(): # ps = graph[s][e]['pts'] # plt.plot(ps[:,1], -ps[:,0], 'red') #print(graph.edges()) print(nx.shortest_path(G, source=0, target=4)) #Draw Edges by 'pts' i = 0 while i < (len(nx.shortest_path(G, source=0, target=4)) - 1):
def to_line_strings(mask, sigma=0.5, threashold=0.3, small_obj_size=300, dilation=1): mask = gaussian(mask, sigma=sigma) mask = mask[..., 0] mask[mask < threashold] = 0 mask[mask >= threashold] = 1 mask = np.array(mask, dtype="uint8") mask = mask[:1300, :1300] mask = cv2.copyMakeBorder(mask, 8, 8, 8, 8, cv2.BORDER_REPLICATE) if dilation > 0: mask = binary_dilation(mask, iterations=dilation) mask, _ = ndimage.label(mask) mask = remove_small_objects(mask, small_obj_size) mask[mask > 0] = 1 ske = np.array(skeletonize(mask), dtype="uint8") ske = ske[8:-8, 8:-8] graph = sknw.build_sknw(ske, multi=True) line_strings = [] lines = [] all_coords = [] node, nodes = graph.node, graph.nodes() # draw edges by pts for (s, e) in graph.edges(): for k in range(len(graph[s][e])): ps = graph[s][e][k]['pts'] coords = [] start = (int(nodes[s]['o'][1]), int(nodes[s]['o'][0])) all_points = set() for i in range(1, len(ps)): pt1 = (int(ps[i - 1][1]), int(ps[i - 1][0])) pt2 = (int(ps[i][1]), int(ps[i][0])) if pt1 not in all_points and pt2 not in all_points: coords.append(pt1) all_points.add(pt1) coords.append(pt2) all_points.add(pt2) end = (int(nodes[e]['o'][1]), int(nodes[e]['o'][0])) same_order = True if len(coords) > 1: same_order = np.math.hypot( start[0] - coords[0][0], start[1] - coords[0][1]) <= np.math.hypot( end[0] - coords[0][0], end[1] - coords[0][1]) if same_order: coords.insert(0, start) coords.append(end) else: coords.insert(0, end) coords.append(start) coords = simplify_coords(coords, 2.0) all_coords.append(coords) for coords in all_coords: if len(coords) > 0: line_obj = LineString(coords) lines.append(line_obj) line_string_wkt = line_obj.wkt line_strings.append(line_string_wkt) new_lines = remove_duplicates(lines) new_lines = filter_lines(new_lines, calculate_node_count(new_lines)) line_strings = [l.wkt for l in new_lines] return line_strings
def to_line_strings(mask, sigma=0.5, threashold=0.3, small_obj_size=300, dilation=1): mask = gaussian(mask, sigma=sigma) mask = mask[..., 0] mask[mask < threashold] = 0 mask[mask >= threashold] = 1 mask = np.array(mask, dtype="uint8") mask = mask[:1300, :1300] mask = cv2.copyMakeBorder(mask, 8, 8, 8, 8, cv2.BORDER_REPLICATE) if dilation > 0: mask = binary_dilation(mask, iterations=dilation) mask, _ = ndimage.label(mask) mask = remove_small_objects(mask, small_obj_size) mask[mask > 0] = 1 ske = np.array(skeletonize(mask), dtype="uint8") ske=ske[8:-8,8:-8] graph = sknw.build_sknw(ske, multi=True) line_strings = [] lines = [] all_coords = [] node, nodes = graph.node, graph.nodes() # draw edges by pts for (s, e) in graph.edges(): for k in range(len(graph[s][e])): ps = graph[s][e][k]['pts'] coords = [] start = (int(nodes[s]['o'][1]), int(nodes[s]['o'][0])) all_points = set() for i in range(1, len(ps)): pt1 = (int(ps[i - 1][1]), int(ps[i - 1][0])) pt2 = (int(ps[i][1]), int(ps[i][0])) if pt1 not in all_points and pt2 not in all_points: coords.append(pt1) all_points.add(pt1) coords.append(pt2) all_points.add(pt2) end = (int(nodes[e]['o'][1]), int(nodes[e]['o'][0])) same_order = True if len(coords) > 1: same_order = np.math.hypot(start[0] - coords[0][0], start[1] - coords[0][1]) <= np.math.hypot(end[0] - coords[0][0], end[1] - coords[0][1]) if same_order: coords.insert(0, start) coords.append(end) else: coords.insert(0, end) coords.append(start) coords = simplify_coords(coords, 2.0) all_coords.append(coords) for coords in all_coords: if len(coords) > 0: line_obj = LineString(coords) lines.append(line_obj) line_string_wkt = line_obj.wkt line_strings.append(line_string_wkt) new_lines = remove_duplicates(lines) new_lines = filter_lines(new_lines, calculate_node_count(new_lines)) line_strings = [ l.wkt for l in new_lines] return line_strings
def analyze(self, plant, side, c_entry, min_area): self.plant = plant self.side = side self.c_entry = c_entry self.min_area = min_area self.progress = 0 '''Does image analysis on the file and outputs the lengths''' self.overlay = self.img.copy() if self.plant == "coleoptile": img2 = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY) median = cv2.medianBlur(img2, 5) blur = cv2.bilateralFilter(median, 9, 75, 75) _, mask = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) elif self.plant == "seedling": img2 = cv2.cvtColor(self.img, cv2.COLOR_BGR2HSV) median = cv2.medianBlur(img2, 5) blur = cv2.bilateralFilter(median, 9, 75, 75) lower_thres = np.array( [self.hue_lower, self.sat_lower, self.val_lower]) upper_thres = np.array( [self.hue_upper, self.sat_upper, self.val_upper]) mask = cv2.inRange(blur, lower_thres, upper_thres) # Noise removal with opening and closing kernel = np.ones((5, 5), np.uint8) closing = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # Calibration if self.side == "right": cal = blur[self.img.shape[0]-self.img.shape[0]//5:,\ self.img.shape[1]-self.img.shape[1]//5:] elif self.side == "left": cal = blur[self.img.shape[0]-self.img.shape[0]//5:,\ :self.img.shape[1]//5] # Thresholding and stuff for calibrator if self.plant == "seedling": cal = cv2.split(cal)[2] # Get grayscale _, calth = cv2.threshold(cal, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) calcont = cv2.findContours(calth, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[1] maxArea = 0 for contour in calcont: # Calibrator is the biggest contour in that region if cv2.contourArea(contour) > maxArea: scale = cv2.boundingRect(contour)[2] maxArea = cv2.contourArea(contour) # For displaying the results self.result = [] self.firstline = "Calibration: {}mm={} pixels; 1 pixel={:.3f}mm\n\n".format(\ self.c_entry, scale, self.c_entry/scale) self.result.append(self.firstline) # Core of the program...one line contours = cv2.findContours(closing, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[1] # Progress bar progress = len( [x for x in contours if cv2.contourArea(x) > self.min_area]) print("Progress: [{}]".format(" " * 30), end='') print("\b" * 31, end='') stdout.flush() # Initialization cc = 0 all_results = [] for contour in contours: # Detects only large enough contours if cv2.contourArea(contour) < self.min_area: continue cc += 1 temp_results = [str(cc)] # Draw just one contour and skeletonize it temp_array = np.zeros(closing.shape, dtype=np.uint8) cv2.fillPoly(temp_array, [contour], color=(255, 255, 255)) skeltest = skeletonize(temp_array / 255) graph = sknw.build_sknw(skeltest) # Build graph # Prune the graph only for seedlings if self.plant == "seedling": degree_list = [ node for node, degree in graph.degree if degree == 1 ] # List of terminal nodes while degree_list: node = degree_list[0] neighbor = list(graph.neighbors(node))[0] # If the edge is shorter than a threshold and it's not the lowest node # and there isn't just two nodes left... if graph[node][neighbor]['weight'] < 50 and node != list(graph.nodes)[-1]\ and graph.degree(neighbor) != 1: graph.remove_node(node) # If neighbor becomes terminal node, add to the list if graph.degree(neighbor) == 1: degree_list.append(neighbor) degree_list.pop(0) # Pruning again - remove repeat edges (RARE) for x, y in graph.edges: if x == y: graph.remove_edge(x, y) # Some useful values node, nodes = graph.nodes, list(graph.nodes) branch_pts = [key for key, value in graph.degree if value == 3] branch_pts.sort(reverse=True) # TOTAL SHOOT LENGTH # For coleoptile, get the longest path possible if self.plant == "coleoptile": length = max(nx.single_source_dijkstra_path_length(graph,\ nodes[-1]).values()) branch_pts = [] # For seedling, get length from lowest to highest node (= plant length) elif self.plant == "seedling": length = nx.dijkstra_path_length(graph, nodes[-1], nodes[0]) temp_results.append(length * self.c_entry / scale) # LEAF LENGTHS AND INTERNODES for i in range(len(branch_pts)): branch_pt = branch_pts[i] # Select the two "higher" nodes from the neighbors n1, n2, _ = sorted(graph.neighbors(branch_pt)) # If it's not the last branch if i != len(branch_pts) - 1: # Internode length interLength = nx.dijkstra_path_length( graph, branch_pt, branch_pts[i + 1]) # Determine leaf node - it's the one NOT in the longest path if n1 in nx.dijkstra_path(graph, nodes[-1], nodes[0]): leaf_node = self.findTerminalNode(graph, branch_pt, n2) else: leaf_node = self.findTerminalNode(graph, branch_pt, n1) # Append results without correction if i != 0: temp_results.append(interLength * self.c_entry / scale) # For the last branch, determine leaf using distance with internode line else: # Approximate orientation by using 100 points below the branching point # Main one: if there is more than one leaf if len(branch_pts) != 1: # Get all the internode points inter = self.mergePoints(graph, branch_pt, branch_pts[i - 1]) # If the internode is really short, use the first hundred points if len(inter) < 150: inter = inter[:100] # This one uses points a bit further down -> more accurate else: inter = inter[49:149] interApprox1 = inter[0][::-1] interApprox2 = inter[-1][::-1] # Only one branching point, use point above the branching point else: path = nx.dijkstra_path(graph, nodes[-1], nodes[0]) interApprox1 = node[branch_pt]['o'][::-1] interApprox2 = graph[branch_pt][path[path.index(branch_pt)+1]]\ ['pts'][-100:][0][::-1] # Compare the distance at the same y point - determine long and short node l_node, l_pts, s_node, s_pts = self.compareNodes( n1, n2, graph, branch_pt) # Starting point for longer node try: start_pt = list(l_pts[:, 0]).index( round(node[s_node]['o'][0])) except ValueError: start_pt = 0 # Get the maximum distance from all points on node-branch point edge # to the internode line s_dist = max([self.distanceWiki(interApprox1, interApprox2, each_pt[::-1])\ for each_pt in s_pts]) l_dist = max([self.distanceWiki(interApprox1, interApprox2, each_pt[::-1])\ for each_pt in l_pts[start_pt:]]) # The one with the larger maximum distance is the leaf if l_dist > s_dist: leaf_node = l_node else: leaf_node = s_node leafLength = nx.dijkstra_path_length(graph, branch_pt, leaf_node) # Draw leaf leaf_pts = self.mergePoints(graph, leaf_node, branch_pt) leaf_pts = np.concatenate((leaf_pts[:, [1]], leaf_pts[:, [0]]), 1) cv2.polylines(self.overlay, np.int32([leaf_pts]), False, (0, 255, 255), 5) # For the first branching point, correct the distance using the distance # from the lowest node to the first branch point if i == 0: correction = nx.dijkstra_path_length( graph, nodes[-1], branch_pt) # More than one branching point, there is internode if len(branch_pts) != 1: # Fixed weighted average interLength += 0.7 * correction temp_results.append(interLength * self.c_entry / scale) # Fixed weighted average leafLength += 0.8 * correction temp_results.append(leafLength * self.c_entry / scale) x, y, w, h = cv2.boundingRect(contour) # Drawing bounding box and put text cv2.rectangle(self.overlay, (x, y), (x + w, y + h), (0, 0, 255), 5) cv2.putText(self.overlay,str(cc),(x-15,y-15),cv2.FONT_HERSHEY_SIMPLEX,\ 4, (0,0,255),5) # Results order: total length, internode 1, leaf 1, internode 2, leaf 2, leaf 3, ... all_results.append(temp_results) # Progress bar :) (look at terminal) print('#' * (int(cc / progress * 30) - int( (cc - 1) / progress * 30)), end='') stdout.flush() self.progress = (cc / progress) * 100 self.results = {1: {'val': all_results}} # For grouping self.calcStatistics() self.showText() # Display new image with bounding box b, g, r = cv2.split(self.overlay) temp = cv2.merge((r, g, b)) #temp = Image.fromarray(temp) self.showImg(temp) #self.flushResults() # Checkpoint self.analyzed = True return True, self.results
def build_graph_single(datapath, debug=False, threshes=0.5, add_small=True, fix_borders=False, reverse=False, inputTiff=None): city = os.path.splitext(datapath)[0].split('/')[-1] img_copy, ske = make_skeleton(datapath, debug, threshes, fix_borders, reverse) if ske is None: print(datapath) print('[I] ske is None') return city, [linestring.format("EMPTY")] G = sknw.build_sknw(ske, multi=True) remove_small_terminal(G) node_lines = graph2lines(G) if not node_lines: print(datapath) return city, [linestring.format("EMPTY")] node = G.node deg = G.degree() wkt = [] terminal_points = [i for i, d in deg.items() if d == 1] terminal_lines = {} vertices = [] for w in node_lines: coord_list = [] additional_paths = [] for s, e in pairwise(w): vals = flatten([[v] for v in G[s][e].values()]) for ix, val in enumerate(vals): s_coord, e_coord = node[s]['o'], node[e]['o'] pts = val.get('pts', []) if s in terminal_points: terminal_lines[s] = (s_coord, e_coord) if e in terminal_points: terminal_lines[e] = (e_coord, s_coord) ps = add_direction_change_nodes(pts, s, e, s_coord, e_coord) if len(ps.shape) < 2 or len(ps) < 2: continue if len(ps) == 2 and np.all(ps[0] == ps[1]): continue ps_ = np.zeros_like(ps) * 1.00 dataset = gdal.Open(inputTiff) trans = dataset.GetGeoTransform() #print(ps) ps_[:, 1] = trans[0] * 1.0 + ps[:, 1] * 1.0 * trans[ 1] + ps[:, 0] * 1.0 * trans[2] ps_[:, 0] = trans[3] * 1.0 + ps[:, 1] * 1.0 * trans[ 4] + ps[:, 0] * 1.0 * trans[5] #print(ps_) line_strings = [ "{1:.10f} {0:.10f}".format(*c.tolist()) for c in ps_ ] if ix == 0: coord_list.extend(line_strings) else: additional_paths.append(line_strings) vertices.append(ps_) if not len(coord_list): continue segments = remove_duplicate_segments(coord_list) for coord_list in segments: if len(coord_list) > 1: line = '(' + ", ".join(coord_list) + ')' wkt.append(linestring.format(line)) for line_strings in additional_paths: line = ", ".join(line_strings) line_rev = ", ".join(reversed(line_strings)) for s in wkt: if line in s or line_rev in s: break else: wkt.append(linestring.format('(' + line + ')')) if add_small and len(terminal_points) > 1: pass #wkt.extend(add_small_segments(G, terminal_points, terminal_lines)) if debug: vertices = flatten(vertices) visualize(img_copy, G, vertices) if not wkt: return city, [linestring.format("EMPTY")] return city, wkt
def extract_graphs(skeletons): graphs = [sknw.build_sknw(ske) for ske in skeletons] for G in graphs: G.remove_nodes_from(list(nx.isolates(G))) return graphs
for i in range(len(projection)): if projection[i] in nMaximumPeaks: maximumPeakPos.append(i) # print(maximumPeakPos) for point in maximumPeakPos: segment_skeleton[:, point] = 1 segment_skeleton[int(h / 2), point + 1] = 1 segment_skeleton[int(h / 2), point - 1] = 1 # show_img(segment_skeleton) cv2.imwrite(cwd + "/debug/VL_image.png", convert_binary_to_normal_im(segment_skeleton)) # Step 3: Seek and seperate the shortest bridges between every VL pair graph = sknw.build_sknw(segment_skeleton) node, nodes = graph.node, graph.nodes() coordinates = [get_node_coordinate(graph, n) for n in nodes] centerOfVLs = [[int(h / 2), p] for p in maximumPeakPos] nodesOfVLs = [] for point in centerOfVLs: for index in range(len(coordinates)): if (point in coordinates[index].tolist()): nodesOfVLs.append(index) print(nodesOfVLs) result = find_bridges_between_VLs(segment_skeleton, graph, [25, 22]) # # result = np.reshape(result, (len(result),1)) # # print("Shape: ", np.shape(result)) # x = [result[i][0] for i in range(len(result))]
def build_graph(root, fn, debug=False, threshes={'2': .3, '3': .3, '4': .3, '5': .2}, add_small=True, fix_borders=True): # city = os.path.splitext(fn)[0][5:] city = fn img_copy, ske = make_skeleton(root, fn, debug, threshes, fix_borders) if ske is None: return city, [linestring.format("EMPTY")] G = sknw.build_sknw(ske, multi=True) print(fn) print(G) remove_small_terminal(G) node_lines = graph2lines(G) if not node_lines: return city, [linestring.format("EMPTY")] node = G.node deg = G.degree() wkt = [] # terminal_points = [i for i, d in deg.items() if d == 1] terminal_points = [i for i, d in dict(deg).items() if d == 1] terminal_lines = {} vertices = [] for w in node_lines: coord_list = [] additional_paths = [] for s, e in pairwise(w): vals = flatten([[v] for v in G[s][e].values()]) for ix, val in enumerate(vals): s_coord, e_coord = node[s]['o'], node[e]['o'] pts = val.get('pts', []) if s in terminal_points: terminal_lines[s] = (s_coord, e_coord) if e in terminal_points: terminal_lines[e] = (e_coord, s_coord) ps = add_direction_change_nodes(pts, s, e, s_coord, e_coord) if len(ps.shape) < 2 or len(ps) < 2: continue if len(ps) == 2 and np.all(ps[0] == ps[1]): continue line_strings = ["{1:.1f} {0:.1f}".format(*c.tolist()) for c in ps] if ix == 0: coord_list.extend(line_strings) else: additional_paths.append(line_strings) vertices.append(ps) if not len(coord_list): continue segments = remove_duplicate_segments(coord_list) for coord_list in segments: if len(coord_list) > 1: line = '(' + ", ".join(coord_list) + ')' wkt.append(linestring.format(line)) for line_strings in additional_paths: line = ", ".join(line_strings) line_rev = ", ".join(reversed(line_strings)) for s in wkt: if line in s or line_rev in s: break else: wkt.append(linestring.format('(' + line + ')')) if add_small and len(terminal_points) > 1: wkt.extend(add_small_segments(G, terminal_points, terminal_lines)) if debug: vertices = flatten(vertices) visualize(img_copy, G, vertices) if not wkt: return city, [linestring.format("EMPTY")] return city, wkt
def vectorize(blob): (skel, dist), path = blob logger.info(f"Vectorizing {path}...") graph = sknw.build_sknw(skel) df = gpd.GeoDataFrame(columns=['geometry', 'width']) ul, lr = get_geotiff_bbox(path) dy = ul[0] - lr[0] dx = lr[1] - ul[1] for s, e in graph.edges(): H, W = dist.shape widths = [ dist[tuple(pt)] for pt in graph[s][e]['pts'].astype(np.int32) ] width = np.percentile(widths, 33) / H * dy graph[s][e]['pts'] = simplify_coords(graph[s][e]['pts'], 2.0) # Pop short stubs pops = [] for (s, e) in graph.edges(): if graph[s][e]['weight'] < 10 and (len(graph[s]) == 1 or len(graph[e]) == 1): pops += [(s, e)] for s, e in pops: graph.remove_edge(s, e) # Pop orphaned nodes pops = [] for node in graph.nodes(): if len(graph[node]) == 0: pops += [node] for node in pops: graph.remove_node(node) # Bind nearby point pairs for n1, n2 in combinations(graph.node, 2): diff = la.norm(graph.node[n1]['o'] - graph.node[n2]['o']) if diff < 20 and n2 not in graph[n1]: pts = np.zeros((3, 2)) pts[0, :] = graph.node[n1]['o'] pts[1, :] = (graph.node[n1]['o'] + graph.node[n2]['o']) / 2 pts[2, :] = graph.node[n2]['o'] graph.add_edge(n1, n2, pts=pts, weight=diff) # Bind points along a line for n1 in graph.node: pushes = [] for n2 in graph[n1]: for n3 in graph.node: vec1 = graph.node[n1]['o'] - graph.node[n2]['o'] vec2 = graph.node[n3]['o'] - graph.node[n1]['o'] diff = la.norm(vec2) vec1 /= la.norm(vec1) vec2 /= diff try: angle = np.arccos(vec1 @ vec2) * 180 / np.pi except: logger.critical("Could not compute points on vector!") angle = 90 if abs(angle % 360) < 2 and diff < 150: pts = np.zeros((3, 2)) pts[0, :] = graph.node[n1]['o'] pts[1, :] = (graph.node[n1]['o'] + graph.node[n3]['o']) / 2 pts[2, :] = graph.node[n3]['o'] pushes += [(n1, n3, pts, diff)] for n1, n2, pts, diff in pushes: graph.add_edge(n1, n2, pts=pts, weight=diff) for s, e in graph.edges(): N = len(graph[s][e]['pts']) + 2 pts = np.zeros((N, 2), dtype=np.float64) pts[0] = graph.node[s]['o'] pts[-1] = graph.node[e]['o'] pts[1:-1] = graph[s][e]['pts'] pts[:, 0] = 1 - pts[:, 0] / H pts[:, 0] *= dy pts[:, 0] += lr[0] pts[:, 1] = pts[:, 1] / W pts[:, 1] *= dx pts[:, 1] += ul[1] df = df.append({ 'geometry': LineString(pts[:, ::-1]), 'width': width }, ignore_index=True) return df