OpenCV Python - 不同的Contour近似方法具有相同的输出

时间:2018-04-03 18:28:45

标签: python image opencv image-processing computer-vision

根据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个点定义,每个角落一个。

2 个答案:

答案 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()

让我们慢慢地浏览代码。代码的第一部分就是您提供的内容。现在我们进入新的目标。

步骤#1 - 使用两种方法检测轮廓

使用阈值图像,我们使用完整和简单近似检测轮廓。这会存储在两个列表中,contours1contours2

步骤#2 - 重塑为2D矩阵

轮廓本身存储为NumPy数组列表。对于提供的简单图像,应该只检测到一个轮廓,因此提取出列表的第一个元素,然后使用numpy.reshape将3D矩阵重新整形为2D形式,其中每行为(x, y)点。

步骤#3 - 将点绘制为图像中的各个圆

下一步是从每组轮廓中取出每个(x, y)点并在图像上绘制它们。我们以彩色形式制作原始图像的两个副本,然后我们使用cv2.circle并遍历每对(x, y)点对两组轮廓进行迭代,并填充两个不同的图像 - 每组轮廓一个。

步骤#4 - 将两个图像并排堆叠并显示

我们最终使用numpy.hstack水平堆叠图像,然后显示结果。您将看到左图像是完整轮廓近似的两个图像,而右图像是简化版本。