OpenCV 从零学习 · 第 8 讲:轮廓查找与绘制
函数:cv2.findContours / cv2.drawContours | 难度:★★☆☆☆
"轮廓"(Contour)是连接所有连续边界点的曲线,代表图像里一个个物体的外形。拿到轮廓后,你就能数物体个数、给目标画框、算面积、识别形状——这是从"边缘线"走向"理解物体"的关键一步。轮廓查找的输入必须是二值图(如 threshold / Canny 的结果)。
一、查找轮廓 cv2.findContours
函数签名(OpenCV 4.x)
contours, hierarchy = cv2.findContours(image, mode, method)
| 参数 | 含义 |
image | 二值图(白=前景)。此函数会原地修改该图,建议传一份副本 |
mode | 轮廓检索模式(见下) |
method | 轮廓近似方法(见下) |
返回值:contours 是一个列表,每个元素是一个形状为 (N,1,2) 的 NumPy 数组,存该轮廓的所有点;hierarchy 是轮廓层级关系(嵌套轮廓时用)。
| mode 取值 | 用途 |
RETR_EXTERNAL | 只取最外层轮廓(忽略内部嵌套),最常用 |
RETR_LIST | 所有轮廓,不建立层级 |
RETR_TREE | 完整层级树(如一个圆里套一个方) |
| method 取值 | 用途 |
CHAIN_APPROX_SIMPLE | 压缩冗余点,只留端点(推荐,省内存) |
CHAIN_APPROX_NONE | 保留轮廓上每一个像素点 |
⚠ 新手必踩坑(版本差异)
OpenCV 4.x(你现在装的)返回两个值:
OpenCV 3.x 返回三个值:
网上老教程多是 3.x 写法,直接抄会"太多值无法解包"报错。本文按 4.x 写。
OpenCV 4.x(你现在装的)返回两个值:
contours, hierarchy = cv2.findContours(...)。OpenCV 3.x 返回三个值:
image, contours, hierarchy = cv2.findContours(...)。网上老教程多是 3.x 写法,直接抄会"太多值无法解包"报错。本文按 4.x 写。
场景 A · 数图里有多少个物体
对一张白底黑块的二值图,
对一张白底黑块的二值图,
RETR_EXTERNAL 找出所有外轮廓,len(contours) 就是物体个数。
import cv2
img = cv2.imread('blocks.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, bin = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV) # 物体变白
contours, _ = cv2.findContours(bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print('物体个数 =', len(contours))
场景 B · 过滤小噪点
二值图常带细小噪点轮廓。用
二值图常带细小噪点轮廓。用
cv2.contourArea(c) 算面积,只保留面积大于某阈值的轮廓,噪点就被去掉了。
二、绘制轮廓 cv2.drawContours
img = cv2.drawContours(img, contours, contourIdx, color, thickness)
| 参数 | 含义 |
img | 要画上去的图(原地修改,无返回值也可用) |
contours | findContours 的返回值 |
contourIdx | 要画的轮廓索引,-1 表示全部 |
color | BGR 颜色,如 (0,0,255) 红 |
thickness | 线宽,-1 表示填充轮廓内部 |
场景 C · 把找到的轮廓描红
cv2.drawContours(img, contours, -1, (0,0,255), 2) 给所有物体描上 2 像素红边。
三、轮廓的常用度量与外接框
| 函数 | 作用 |
cv2.contourArea(c) | 轮廓面积(像素数) |
cv2.arcLength(c, closed) | 周长,closed=True 表示闭合 |
cv2.boundingRect(c) | 返回 (x,y,w,h) 正外接矩形 |
cv2.approxPolyDP(c, eps, closed) | 多边形近似,eps 越大越粗略 |
场景 D · 给每个物体画外接框(目标检测框雏形)
遍历轮廓,对每个算
遍历轮廓,对每个算
x,y,w,h = cv2.boundingRect(c),再用 cv2.rectangle 画框——这就是最简单版的"框出目标"。
场景 E · 用边数判断形状
approx = cv2.approxPolyDP(c, 0.02*cv2.arcLength(c,True), True),看 len(approx):3=三角形、4=矩形/方形、≈10 且接近圆=圆。
for c in contours:
if cv2.contourArea(c) < 100: # 过滤小噪点
continue
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
本讲要点
- 输入二值图;OpenCV 4.x 返回
contours, hierarchy两个值(3.x 是三个,别抄错)。 RETR_EXTERNAL+CHAIN_APPROX_SIMPLE是数物体、画外框的常用组合。- 用面积过滤噪点、用
boundingRect画框、用approxPolyDP判断形状。
下一讲:第 9 讲 · 在图像上画图形与文字(line / rectangle / circle / putText)——把"框、点、标签"真正画出来做标注。
