How to fill in arbitrary closed areas in Matplotlib?

Let me begin with where I:

enter image description here

I created the above image with the following code:

import matplotlib.pyplot as plt import numpy as np color_palette_name = 'gist_heat' cmap = plt.cm.get_cmap(color_palette_name) bgcolor = cmap(np.random.rand()) f = plt.figure(figsize=(12, 12), facecolor=bgcolor,) ax = f.add_subplot(111) ax.axis('off') t = np.linspace(0, 2 * np.pi, 1000) x = np.cos(t) + np.cos(6. * t) / 2.0 + np.sin(14. * t) / 3.0 y = np.sin(t) + np.sin(6. * t) / 2.0 + np.cos(14. * t) / 3.0 ax.plot(x, y, color=cmap(np.random.rand())) ax.fill(x, y, color=cmap(np.random.rand())) plt.tight_layout() plt.savefig("../demo/tricky.png", facecolor=bgcolor, edgecolor=cmap(np.random.rand()), dpi=350) 

Is there a way to fill the loops (or areas similar to triangles) that are created when the line intersects itself with some other color? It should not be matplotlib, it can be a scikit image or some other library.

I think some kind of pseudo code is like:

 for region in regions: ax.fill(region, color=cmap(np.random.rand())) 

But I have no idea how to get regions , or how populating it will work.

+6
source share
1 answer

At first the problem seemed simple to me, my idea was to use blob analysis to detect various drops, group them by size and use the flood-fill algorithm to color them.

However, I ran into some problems with the default values ​​for blob analysis, which I did not change, which was worth some time. In addition, I did not find snippets of code for python to fill fluorescence or stain droplets using OpenCV, and there were some syntactic changes for using SimpleBlobDetection compared to older versions, for which I could only find a small documentation and sample code. Therefore, perhaps all of this code may also be useful to other users.

I hope that I correctly identified the segments that you wanted to find. If you want not to include large dark outer leaves, there is a comment line.

For visualization, you can resize the image (remember at the moment, do not forget to adapt the dimensional thresholds, respectively, to 4 * 4 = 16)

enter image description here

The code is somewhat long with all these parameters, but I hope it is easy to read. I learned a lot from analyzing blob with OpenCV working on this issue, thanks!

Good image, by the way.

 import numpy as np import cv2 im = cv2.imread('tricky.png') # For better visibility, resize image to better fit screen #im= cv2.resize(im, dsize=(0,0),fx=0.25, fy=0.25) #convert to gray value for blob analysis imgray= cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) #### Blob analysis to find inner white leaves # SimpleBlobDetector will find black blobs on white surface, this is why type=cv2.THRESH_BINARY_INV is necessary ret,imthresh = cv2.threshold(imgray,160, 255,type=cv2.THRESH_BINARY_INV) # Setup SimpleBlobDetector parameters. params = cv2.SimpleBlobDetector_Params() # Filter by Area. params.filterByArea = True params.minArea = 15000 params.maxArea = 150000 # Create a detector with the parameters detector = cv2.SimpleBlobDetector_create(params) # Detect blobs. keypoints = detector.detect(imthresh) # Draw detected blobs as red circles. # cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures # the size of the circle corresponds to the size of blob im_with_keypoints = cv2.drawKeypoints(imthresh, keypoints, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) # Show blobs cv2.imshow("Keypoints", im_with_keypoints) ####floodfill inner white leaves with blue #http://docs.opencv.org/3.0-beta/modules/imgproc/doc/miscellaneous_transformations.html #Create a black mask for floodfill. Mask needs to be 2 pixel wider and taller maskborder=imgray.copy() maskborder[:] = 0 bordersize=1 maskborder=cv2.copyMakeBorder(maskborder, top=bordersize, bottom=bordersize, left=bordersize, right=bordersize, borderType= cv2.BORDER_CONSTANT, value=[255,255,255] ) print imgray.shape[:2] print maskborder.shape[:2] #Create result image for floodfill result = im.copy() #fill white inner segments with blue color for k in keypoints: print int(k.pt[0]),int(k.pt[1]) seed_pt = int(k.pt[0]),int(k.pt[1]) cv2.floodFill(result, maskborder, seed_pt, (255,0, 0)) #### Blob analysis to find small triangles # SimpleBlobDetector will find black blobs on white surface, this is why type=cv2.THRESH_BINARY_INV is necessary ret,imthresh2 = cv2.threshold(imgray,150, 255,type=cv2.THRESH_BINARY) ret,imthresh3 = cv2.threshold(imgray,140, 255,type=cv2.THRESH_BINARY_INV) imthresh4 = cv2.add(imthresh2,imthresh3) # Setup SimpleBlobDetector parameters. params = cv2.SimpleBlobDetector_Params() # Filter by Area. params.filterByArea = True params.minArea = 20 params.maxArea = 1000 params.maxArea = 50000 #Using this line includes the outer dark leaves. Comment out if necessary # Don't filter by Circularity params.filterByCircularity = False # Don't filter by Convexity params.filterByConvexity = False # Don't filter by Inertia params.filterByInertia = False # Create a detector with the parameters detector = cv2.SimpleBlobDetector_create(params) # Detect blobs. keypoints = detector.detect(imthresh4) # Draw detected blobs as red circles. # cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures # the size of the circle corresponds to the size of blob im_with_keypoints2 = cv2.drawKeypoints(imthresh4, keypoints, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) # Show blobs cv2.imshow("Keypoints2", im_with_keypoints2) ####floodfill triangles with green #http://docs.opencv.org/3.0-beta/modules/imgproc/doc/miscellaneous_transformations.html #Create a black mask for floodfill. Mask needs to be 2 pixel wider and taller maskborder=imgray.copy() maskborder[:] = 0 bordersize=1 maskborder=cv2.copyMakeBorder(maskborder, top=bordersize, bottom=bordersize, left=bordersize, right=bordersize, borderType= cv2.BORDER_CONSTANT, value=[255,255,255] ) print imgray.shape[:2] print maskborder.shape[:2] #Create result image for floodfill result2 = result.copy() #fill triangles with green color for k in keypoints: print int(k.pt[0]),int(k.pt[1]) seed_pt = int(k.pt[0]),int(k.pt[1]) cv2.floodFill(result2, maskborder, seed_pt, (0,255, 0)) #cv2.imshow('main',im) #cv2.imshow('gray',imgray) #cv2.imshow('borders',maskborder) #cv2.imshow('threshold2',imthresh2) #cv2.imshow('threshold3',imthresh3) #cv2.imshow('threshold4',imthresh4) cv2.imshow("Result", result2) cv2.imwrite("result.png",result2) cv2.waitKey(0) cv2.destroyAllWindows() 
+3
source

All Articles