Find contour of multiple objects with their holes

≯℡__Kan透↙ 提交于 2019-12-11 14:16:32

问题


This is a follow up question from: How to obtain boundary coordinates of binary mask with holes?

Given the same image:

I want to get a separate list for each object of (x, y)-coordinates of the outer contour and its inner contour. Ideally, I want to use this list to plot the object (outer and inner contour) on a separate blank canvas.

import matplotlib.pyplot as plt # For plotting
import cv2
from skimage import io         # Only needed for web grabbing images, use cv2.imread for local images


# Read image; find contours with hierarchy
blob = io.imread('https://i.stack.imgur.com/Ga5Pe.png')
contours, hier = cv2.findContours(blob, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Define sufficient enough colors for blobs
colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]

# Draw all contours, and their children, with different colors
out = cv2.cvtColor(blob, cv2.COLOR_GRAY2BGR)
# Check if it's the outer contour
k = -1
# Preallocate list
obj_list = []

for i, cnt in enumerate(contours):
    if (hier[0, i, 3] == -1):
        k += 1
    # cv2.drawContours(out, [cnt], -1, colors[k], 2)
    # Add contour list to object list if it is an inner contour
    obj_list.extend([cnt])

    # Concatenate array in list    
    obj_list = np.vstack(obj_list)    
    obj_list = np.squeeze(obj_list)   
    x = obj_list[:,0].tolist()    
    y = obj_list[:,1].tolist()


cv2.imshow('out', out)
cv2.waitKey(0)
cv2.destroyAllWindows()

EDIT: The accepted answer only works with objects with inner contours but not for objects without. I tried to fix it by adding the following code:

# Add inner contours of blob to list
cnt_idx = np.squeeze(np.where(hier[0, :, 3] == b_idx))
c_cnt_idx = np.array(cnt_idx)
if c_cnt_idx.size > 0:
    cnt_idx = b_idx

but I received the following error message:

ValueError: Iteration of zero-sized operands is not enabled


回答1:


Then I will also answer this question. Again, I skipped the whole plotting part. And, as suggested in my earlier answer, I modified the finding of the blobs, such that the proper "blob indices" (with respect to the hierarchy) are found beforehand using NumPy.

Here comes the modified code:

import cv2
import numpy as np
from skimage import io         # Only needed for web grabbing images, use cv2.imread for local images

# Read image; add an additional hole; find contours with hierarchy
blob = io.imread('https://i.stack.imgur.com/Ga5Pe.png')
cv2.circle(blob, (380, 120), 25, 0, cv2.FILLED)
contours, hier = cv2.findContours(blob, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Define sufficient enough colors for blobs
colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]

# Get blob indices with respect to hierarchy
blob_idx = np.squeeze(np.where(hier[0, :, 3] == -1))

# Initialize blob images
blob_imgs = []

# Iterate all blobs
k = 0
for b_idx in np.nditer(blob_idx):

    # Add outer contour of blob to list
    blob_cnts = [contours[b_idx]]

    # Add inner contours of blob to list, if present
    cnt_idx = np.squeeze(np.where(hier[0, :, 3] == b_idx))
    if (cnt_idx.size > 0):
        blob_cnts.extend([contours[c_idx] for c_idx in np.nditer(cnt_idx)])

    # Generate blank BGR image with same size as input; draw contours
    img = np.zeros((blob.shape[0], blob.shape[1], 3), np.uint8)
    cv2.drawContours(img, blob_cnts, -1, colors[k], 2)
    blob_imgs.append(img)
    k += 1

# Just for visualization: Iterate all blob images
k = 0
for img in blob_imgs:
    cv2.imshow(str(k), img)
    k += 1
cv2.waitKey(0)
cv2.destroyAllWindows()

The two outputs generated (I added another hole in one of the blobs to check for multiple inner contours):

So, inside the main loop, you now have all contours belonging to one blob stored in blob_cnts, again as lists of (x, y)-coordinates. So, instead of generating different images as shown here, you can generate plots or do whatever you like.

Hope that helps!



来源:https://stackoverflow.com/questions/58970920/find-contour-of-multiple-objects-with-their-holes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!