cv2.findContours()返回函数详解, findContours()

对于cv2.findContours() 函数,相信很多人都在使用,利用其进行轮廓的寻找,之后利用cnt[num],对第num个轮廓进行操作,但是该函数返回的三个参数具体表示的是什么呢?

下面就进行详细介绍,为了能够使读者更加深入的理解,利用下面的例程进行具体分析。

准备材料:图片一张(作者手动画图软件绘制的)


Python程序如下:

improve cv2
improve numpy as np
img=cv2.imread('test.jpg')
imgray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh=cv2.thrshold(imgray,127,255,0)
image,cnts,hierarchy=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow('imageshow',image)  # 显示返回值image,其实与输入参数的thresh原图没啥区别
cv2.waitKey()
print(np.size(cnts))  #   得到该图中总的轮廓数量
print(cnts[0])   #  打印出第一个轮廓的所有点的坐标, 更改此处的0,为0--(总轮廓数-1),可打印出相应轮廓所有点的坐标
print(hierarchy) #打印出相应轮廓之间的关系
img=cv2.drawCountours(img,[cnts
<think>好的,我现在需要详细讲解一下`cv2.findContours`这个函数。首先,用户可能已经遇到了版本问题导致的错误,所以得先明确不同OpenCV版本的差异。之前的对话已经提到过返回值的变化,这里需要再次强调,避免用户混淆。 接下来,得解释函数的基本用途:轮廓检测。用户可能不太清楚轮廓是什么,或者为什么需要检测轮廓。需要简单说明轮廓在图像处理中的应用,比如对象识别、形状分析等。 然后,参数部分需要详细展开。每个参数的作用和可能的值,比如`mode`里的各种检索模式,`method`里的近似方法。可能需要用例子说明不同模式的区别,比如`RETR_EXTERNAL`只找最外层轮廓,而`RETR_TREE`会建立层级关系。 返回值部分,要分版本说明,特别是OpenCV 3.x和4.x的区别。用户可能还在使用旧版本,或者升级后遇到了问题,所以这部分必须清晰。 之后,注意事项也很重要。比如输入图像必须是二值图,否则函数可能无法正确工作。用户可能没有正确预处理图像,导致检测不到轮廓,或者结果不准确,需要提醒这一点。 最后,代码示例是必要的,让用户看到如何实际应用这个函数。示例中应包括读取图像、二值化处理、调用函数、绘制轮廓并显示结果。同时,可以加入版本检查的代码,帮助用户确认自己的OpenCV版本。 还要考虑用户可能的疑问,比如如何处理返回的轮廓数据,层级结构的具体含义,以及不同近似方法对结果的影响。需要用简单易懂的语言解释这些概念,避免过于技术化导致用户困惑。 另外,可能用户对轮廓的具体应用场景不太清楚,可以举几个实际例子,比如检测图像中的物体边界,计算物体的面积或周长,或者用于图像分割等。这些例子能帮助用户更好地理解函数的作用。 最后,总结一下关键点,确保用户能够抓住重点,比如版本差异、参数设置、输入图像要求和实际应用。这样用户在使用函数时就能避免常见错误,正确应用在项目中。</think>--- ### **`cv2.findContours()` 函数详解** `cv2.findContours()` 是 OpenCV 中用于 **检测图像轮廓** 的核心函数,广泛应用于目标识别、形状分析、图像分割等领域。以下从 **功能、参数、返回值、注意事项** 四个维度详细解析: --- ### **1. 核心功能** - **输入**:二值图像(黑白图像,非0即255)。 - **输出**:检测到的轮廓集合及轮廓间的层级关系。 - **原理**:通过扫描图像像素,寻找连续边缘的闭合区域(轮廓),并记录轮廓点的坐标。 --- ### **2. 函数原型** ```python contours, hierarchy = cv2.findContours( image, # 输入二值图像(通常需先经过阈值处理或边缘检测) mode, # 轮廓检索模式(决定如何组织轮廓) method, # 轮廓近似方法(决定如何存储轮廓点) contours=None, # (可选)输出轮廓列表 hierarchy=None, # (可选)输出层级关系 offset=None # (可选)轮廓点坐标偏移量 ) ``` --- ### **3. 参数详解** #### **(1) `mode`:轮廓检索模式** | 模式 | 作用 | |--------------------------|---------------------------------------------------------------------| | `cv2.RETR_EXTERNAL` | 仅检测最外层轮廓(忽略嵌套轮廓) | | `cv2.RETR_LIST` | 检测所有轮廓,不建立层级关系 | | `cv2.RETR_CCOMP` | 检测所有轮廓,组织为两级层级(外层轮廓和其内部孔洞) | | `cv2.RETR_TREE` | 检测所有轮廓,建立完整的层级树结构(记录父子关系) | #### **(2) `method`:轮廓近似方法** | 方法 | 作用 | |--------------------------|---------------------------------------------------------------------| | `cv2.CHAIN_APPROX_NONE` | 存储所有轮廓点(坐标完整,但占用内存大) | | `cv2.CHAIN_APPROX_SIMPLE`| 压缩冗余点(如直线仅保留端点,节省内存) | | `cv2.CHAIN_APPROX_TC89_L1` | 使用 Teh-Chin 链式近似算法(优化轮廓点) | --- ### **4. 返回值** - **OpenCV 3.x 版本**:返回 **3 个值** ```python image, contours, hierarchy = cv2.findContours(...) ``` - `image`:处理后的图像(OpenCV 4.x 已废弃此返回值)。 - `contours`:轮廓列表,每个轮廓是 Numpy 数组,存储轮廓点坐标。 - `hierarchy`:轮廓的层级关系(形状为 `[1, N, 4]` 的数组)。 - **OpenCV 4.x 版本**:返回 **2 个值** ```python contours, hierarchy = cv2.findContours(...) ``` --- ### **5. 关键注意事项** #### **(1) 输入图像必须为二值图像** - 若图像非二值,需先进行预处理: ```python # 示例:通过阈值处理生成二值图像 _, binary = cv2.threshold(gray_image, 127, 255, cv2.THRESH_BINARY) ``` #### **(2) 轮廓数据的结构** - `contours` 是列表,每个元素对应一个轮廓。 - 单个轮廓是形状为 `(N, 1, 2)` 的数组,表示 N 个点的 (x, y) 坐标: ```python contour = contours[0] # 获取第一个轮廓 print(contour.shape) # 输出:(N, 1, 2) ``` #### **(3) 层级关系 `hierarchy`** - 每个轮廓的层级信息由 `[Next, Previous, First_Child, Parent]` 组成: - `Next`:同一层级的下一个轮廓索引(-1 表示无)。 - `Previous`:同一层级的上一个轮廓索引(-1 表示无)。 - `First_Child`:第一个子轮廓索引(-1 表示无)。 - `Parent`:父轮廓索引(-1 表示无)。 --- ### **6. 代码示例** #### **(1) 基础用法(检测并绘制轮廓)** ```python import cv2 # 读取图像并二值化 image = cv2.imread("shape.png", 0) # 灰度模式读取 _, binary = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY) # 检测轮廓(OpenCV 4.x) contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 在原图上绘制轮廓 result = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) cv2.drawContours(result, contours, -1, (0, 255, 0), 2) # 绿色线条,线宽2 cv2.imshow("Contours", result) cv2.waitKey(0) ``` #### **(2) 获取轮廓属性** ```python # 计算轮廓面积和周长 for i, cnt in enumerate(contours): area = cv2.contourArea(cnt) perimeter = cv2.arcLength(cnt, closed=True) print(f"Contour {i}: Area={area}, Perimeter={perimeter}") ``` --- ### **7. 常见问题** #### **Q1:为什么检测不到轮廓?** - 可能原因:输入图像非二值、背景与前景颜色颠倒、阈值处理不当。 - 解决方法:检查图像预处理步骤,确保目标区域为白色(255)。 #### **Q2:如何过滤小面积轮廓?** ```python min_area = 100 filtered_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > min_area] ``` #### **Q3:如何处理返回的层级关系?** - 示例:遍历所有轮廓并打印父子关系: ```python for i in range(len(contours)): print(f"Contour {i}: Child={hierarchy[0][i][2]}, Parent={hierarchy[0][i][3]}") ``` --- ### **8. 总结** | **核心要点** | **说明** | |----------------------------|-------------------------------------------------------------------------| | **版本兼容性** | OpenCV 4.x 仅返回 `contours` 和 `hierarchy` | | **输入图像要求** | 必须为二值图像 | | **轮廓检索模式选择** | 根据需求选择 `RETR_EXTERNAL`(外层)或 `RETR_TREE`(全层级) | | **轮廓近似方法优化** | 优先使用 `CHAIN_APPROX_SIMPLE` 节省内存 | | **实际应用场景** | 物体计数、形状匹配、缺陷检测、OCR 预处理等 | 通过掌握 `cv2.findContours()` 的核心参数和返回值逻辑,可高效实现复杂图像分析任务。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值