根据this Python教程, OpenCV cv2.findContours 功能有两种轮廓逼近方法: cv2.CHAIN_APPROX_NONE 和 cv2.CHAIN_APPROX_SIMPLE 。第一个存储所有边界点,第二个方法删除所有冗余点。
import cv2
im = cv2.imread('simple.jpg')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
_, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
img = cv2.drawContours(im, contours, -1, (0, 255, 0), 3)
cv2.imshow('Output', img)
wk = cv2.waitKey(0) & 0xFF
if wk == 27:
cv2.destroyAllWindows()
但无论使用何种方法,此代码都会输出相同的图像。
这是代码执行后的图像: Output
绿线是轮廓。正如您所看到的,矩形被绿线包围,但它应该只由4个点定义,每个角落一个。
答案 0 :(得分:2)
我猜它是因为你使用的是drawContours()函数,它按字面意思绘制轮廓。如果你想看到差异,即只想点,我认为你应该尝试绘制返回的点,而不是使用drawContours()函数。
答案 1 :(得分:1)
如果你看一下教程,特别是在文本的底部,它是:
只需在轮廓阵列中的所有坐标上绘制一个圆圈(以蓝色绘制)。
Mehul Jain是正确的,如果使用cv2.drawContours
,它只是在绘制轮廓时将点连接在一起。您不会明显看到两种近似方法之间的差异。您需要做的是绘制圆圈。
因此,运行cv2.findContours
后,您可以使用contours
输出,该输出是图像中找到的所有轮廓的列表。因为只有一个可能的轮廓,因为它是一个正方形,所以列表应该是一个元素长。另请注意,输出将是(N, 1, 2)
3D NumPy数组,因此最好在继续之前将其重新整形为2列数组。
接下来,您可以使用cv2.circle
实际拍摄每个点并绘制单个圆圈而不是实际轮廓。只有这样你才能真正看到差异。
上面的代码并修改它以便我们执行这两种方法,我们应该这样做:
### Your code
import numpy as np
import cv2
im = cv2.imread('simple.jpg')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
### Step #1
# Detect contours using both methods on the same image
_, contours1, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
_, contours2, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
### Step #2 - Reshape to 2D matrices
contours1 = contours1[0].reshape(-1,2)
contours2 = contours2[0].reshape(-1,2)
### Step #3 - Draw the points as individual circles in the image
img1 = im.copy()
img2 = im.copy()
for (x, y) in contours1:
cv2.circle(img1, (x, y), 1, (255, 0, 0), 3)
for (x, y) in contours2:
cv2.circle(img2, (x, y), 1, (255, 0, 0), 3)
### Step #4 - Stack the two images side by side and show it
out = np.hstack([img1, img2])
cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
让我们慢慢地浏览代码。代码的第一部分就是您提供的内容。现在我们进入新的目标。
使用阈值图像,我们使用完整和简单近似检测轮廓。这会存储在两个列表中,contours1
和contours2
。
轮廓本身存储为NumPy数组列表。对于提供的简单图像,应该只检测到一个轮廓,因此提取出列表的第一个元素,然后使用numpy.reshape
将3D矩阵重新整形为2D形式,其中每行为(x, y)
点。
下一步是从每组轮廓中取出每个(x, y)
点并在图像上绘制它们。我们以彩色形式制作原始图像的两个副本,然后我们使用cv2.circle
并遍历每对(x, y)
点对两组轮廓进行迭代,并填充两个不同的图像 - 每组轮廓一个。
我们最终使用numpy.hstack
水平堆叠图像,然后显示结果。您将看到左图像是完整轮廓近似的两个图像,而右图像是简化版本。