查找多个对象的轮廓及其孔
Find contour of multiple objects with their holes
这是后续问题:
给出相同的图像:
我想为外轮廓及其内轮廓的 (x, y)
坐标的每个对象获取一个单独的列表。理想情况下,我想使用此列表在单独的空白 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()
编辑:
接受的答案仅适用于具有内部轮廓的对象,但不适用于没有内部轮廓的对象。我尝试通过添加以下代码来修复它:
# 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
但我收到以下错误消息:
ValueError: Iteration of zero-sized operands is not enabled
那我也来回答一下这个问题。同样,我跳过了整个绘图部分。而且,正如我之前的回答中所建议的,我修改了 blob 的发现,以便使用 NumPy 预先找到正确的 "blob indices"(关于层次结构)。
修改后的代码来了:
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()
生成的两个输出(我在其中一个斑点中添加了另一个孔以检查多个内部轮廓):
因此,在主循环内,您现在将属于一个 blob 的所有轮廓存储在 blob_cnts
中,同样作为 (x, y)
坐标列表。因此,您可以生成绘图或做任何您喜欢的事情,而不是像这里显示的那样生成不同的图像。
希望对您有所帮助!
这是后续问题:
给出相同的图像:
我想为外轮廓及其内轮廓的 (x, y)
坐标的每个对象获取一个单独的列表。理想情况下,我想使用此列表在单独的空白 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()
编辑: 接受的答案仅适用于具有内部轮廓的对象,但不适用于没有内部轮廓的对象。我尝试通过添加以下代码来修复它:
# 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
但我收到以下错误消息:
ValueError: Iteration of zero-sized operands is not enabled
那我也来回答一下这个问题。同样,我跳过了整个绘图部分。而且,正如我之前的回答中所建议的,我修改了 blob 的发现,以便使用 NumPy 预先找到正确的 "blob indices"(关于层次结构)。
修改后的代码来了:
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()
生成的两个输出(我在其中一个斑点中添加了另一个孔以检查多个内部轮廓):
因此,在主循环内,您现在将属于一个 blob 的所有轮廓存储在 blob_cnts
中,同样作为 (x, y)
坐标列表。因此,您可以生成绘图或做任何您喜欢的事情,而不是像这里显示的那样生成不同的图像。
希望对您有所帮助!