如何在OpenCV 4.4.0版本中正确使用cv2.findContours()函数?

11

我尝试在OpenCV 4.4.0上使用cv2.findContours()(使用Python版本3.8.5),但它会抛出一个错误,我无法解决。我不确定代码有什么问题。这里是一些背景信息:

根据OpenCV的文档,cv2.findContours()的语法如下:

Python: contours, hierarchy = cv.findContours(image, mode, method[, contours[, hierarchy[, offset]]])

我查找了一些示例以确保正确地实现它,以下是我发现的两个示例:

  • 示例1

    (_, contours, _) = cv2.findContours(binary_image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

  • 示例2

    (_, cnts, _) = cv2.findContours(thresholded.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

这些是我在线找到的工作项目中的示例之一,类似的示例有很多。因此,我正在尝试实现从视频中获取的代码以了解更多有关该主题的内容,但它似乎对我不起作用,我找不到原因。以下是代码:

import cv2 
import numpy as np 

imagen =cv2.imread('lettuce.jpg')
gray = cv2.cvtColor(imagen,cv2.COLOR_BGR2GRAY)
_,binary = cv2.threshold(gray,100,255,cv2.THRESH_BINARY)

image,contours,hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

cv2.drawContours(image,contours, -1, (0,255,0),3)

错误:

Traceback (most recent call last):
  line 8, in <module>
    image,contours,hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
ValueError: not enough values to unpack (expected 3, got 2)

请检查答案,如果解决了问题,请将其标记为答案。 - Sivaram Rasathurai
3个回答

15
在Python/OpenCV 4.4.0中,findContours函数只返回2个值,但您列出了3个值。

您展示的内容:

image,contours,hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

OpenCV 4.4.0,清单:

contours, hierarchy = cv.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
请始终查看文档。请参见:https://docs.opencv.org/4.4.0/d3/dc0/group__imgproc__shape.html#gadf1ad6a0b82947fa1fe3c3d497f260e0。如果你只想要轮廓,并且希望以版本无关的方式处理它,一种方法是(@nathancy提出的):
contours = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
如果你不想要所有嵌套轮廓,那么请使用RETR_EXTERNAL而不是RETR_LIST。

1
一些 Python 语法,可以匹配 (*_, contours, hierarchy) = cv.findContours(...) 这将通过名称匹配最后两个元素,并将“剩余部分”(前缀)匹配到 _ 这是规范的“不关心”变量 - Christoph Rackwitz

3
问题在于cv2.findContour函数返回两个值而不是三个。
  • 轮廓(contours)
  • 层次结构(hierarchy)

这个cv2.findContours函数有三个输入参数。第一个参数为灰度图像,第二个参数为检索模式(retrieval mode),第三个参数为逼近方法(approximation mode)。当我们应用findContours方法时,原始图像会受到影响。最佳实践是在处理findContours方法之前对图像进行拷贝。

OpenCV将轮廓存储在列表的列表中。每个列表代表不同的轮廓,在列表内添加该轮廓的所有坐标。 我们可以以不同的方式存储这些坐标。如何存储呢?逼近方法就起到了作用。

使用cv2.CHAIN_APPROX_NONE存储所有边界点。但我们并不一定需要所有边界点。如果这些点形成一条直线,我们只需要该线的起始点和结束点。使用cv2.CHAIN_APPROX_SIMPLE提供了这些边框轮廓的起始和终止点,因此轮廓信息的存储更加高效。

检索模式是什么?检索模式主要定义轮廓的层次结构,就像层次结构是想要子轮廓还是外轮廓或所有轮廓。

在OpenCV中有四种检索模式。

  • cv2.RETR_LIST → 检索所有轮廓
  • cv2.RETR_EXTERNAL → 仅检索外部轮廓
  • cv2.RETR_COMP → 在2级层次结构中检索所有轮廓
  • cv2.RETR_TREE → 检索完整的层次结构中所有轮廓

层次结构以以下格式存储[next, previous, First child, parent]。


1
在OpenCV 4.4.0中,findContours函数只返回2个参数:轮廓(contours)和层级(hierarchy)。 - fmw42
@fmw42,你能解决这个问题吗?https://dev59.com/-ek5XIcBkEYKwwoY3dT9 - Sivaram Rasathurai
1
我已经发布了一个解决方案。 - fmw42

0

这里有另一种方法可以存储从cv2.findContours()返回的所有元组,而不管您的系统/环境中安装的OpenCV版本:

首先,获取已安装的OpenCV版本(我们不需要整个版本,只需要主要数字3或4):

import cv2
major_number = cv2.__version__[0]

根据版本,将执行以下两个语句之一,并填充相应的变量:

if major_number == '4':
    contours, hierarchy = cv2.findContours(img_binary, cv2.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

elif major_number == '3':
    img, contours, hierarchy = cv2.findContours(img_binary, cv2.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

函数返回的轮廓将在两种情况下存储在contours中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接