OpenCV 图像轮廓检测
目录
一、轮廓检测基础概念
二、核心 API 详解:cv2.findContours ()
参数说明:
返回值说明:
三、轮廓检测实战步骤
1. 图像预处理(灰度化与二值化)
2. 查找轮廓
3. 绘制轮廓
四、轮廓的常用属性与操作
1. 轮廓面积与周长
2. 轮廓筛选与排序
3. 轮廓的外接形状
4. 轮廓近似
五、总结
在计算机视觉领域,轮廓检测是一项基础且重要的技术,它能够帮助我们识别图像中的物体边界,为后续的图像分析、目标识别等任务提供关键信息。本文将基于 OpenCV 库,详细介绍轮廓检测的原理、常用 API 及实战应用。
一、轮廓检测基础概念
轮廓可以理解为图像中具有相同颜色或灰度的连续点组成的曲线,它是物体边界的有效表达方式。在进行轮廓检测前,有一个重要的前提:需要将图片处理为二值图像(像素值只为 0 和 255),这是因为轮廓检测主要基于图像的边缘信息,二值化处理能简化后续的检测过程。
二、核心 API 详解:cv2.findContours ()
OpenCV 提供了 cv2.findContours()
函数用于检测图像轮廓,其语法格式如下:
参数说明:
-
img:需要进行轮廓检测的输入图像(必须是二值图像)
-
mode:轮廓的检索模式,常用的有以下四种:
cv2.RETR_EXTERNAL
:只检测外轮廓,忽略所有子轮廓cv2.RETR_LIST
:检测所有轮廓,但不建立等级关系cv2.RETR_CCOMP
:返回所有轮廓,仅建立两级层次结构(外轮廓为第 1 级,内部中空轮廓为第 2 级)cv2.RETR_TREE
:返回所有轮廓,建立完整的层级组织结构
-
method:轮廓的近似方法:
cv2.CHAIN_APPROX_NONE
:存储所有的轮廓点cv2.CHAIN_APPROX_SIMPLE
:压缩模式,只保留轮廓方向的终点坐标(如矩形仅保留 4 个顶点)
返回值说明:
- image:处理后的图像(与输入图像相关)
- contours:包含所有轮廓的列表,每个轮廓是由边界点坐标 (x,y) 组成的 numpy 数组
- hierarchy:轮廓的层次结构,每个元素是包含 4 个值的数组
[Next, Previous, First Child, Parent]
,分别表示:- Next:同一层级的下一条轮廓
- Previous:同一层级的上一条轮廓
- First Child:当前轮廓的第一条子轮廓
- Parent:当前轮廓的父轮廓
注意:在新版 OpenCV(如 4.x 版本)中,该函数返回值为 (contours, hierarchy),可使用
contours = cv2.findContours(...)[-2]
兼容不同版本。
三、轮廓检测实战步骤
1. 图像预处理(灰度化与二值化)
轮廓检测前必须进行预处理,将彩色图像转为灰度图,再进一步转为二值图:
import cv2# 读取原图
phone = cv2.imread('phone.png')
# 转为灰度图
phone_gray = cv2.cvtColor(phone, cv2.COLOR_BGR2GRAY)
# 二值化处理(阈值 120,最大值 255,二值化方式)
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)# 显示处理结果
cv2.imshow('phone_gray', phone_gray)
cv2.imshow('phone_binary', phone_binary)
cv2.waitKey(0)
2. 查找轮廓
使用 cv2.findContours()
函数检测轮廓:
# 查找轮廓(建立完整层级,压缩轮廓点)
_, contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)# 打印轮廓信息
print("轮廓层次结构:", hierarchy)
print("轮廓数量:", len(contours))
轮廓层次结构: [[[ 6 -1 1 -1][ 2 -1 -1 0][ 3 1 -1 0][ 4 2 -1 0][ 5 3 -1 0][-1 4 -1 0][ 7 0 -1 -1][ 8 6 -1 -1][-1 7 -1 -1]]]
轮廓数量: 9
3. 绘制轮廓
通过 cv2.drawContours()
函数可以将检测到的轮廓绘制在图像上:
# 函数语法
# cv2.drawContours(image, contours, contourIdx, color, thickness)# 复制原图避免修改原图
image_copy = phone.copy()
# 绘制所有轮廓(contourIdx=-1),绿色(0,255,0),线宽 2
cv2.drawContours(image_copy, contours, -1, (0,255,0), 2)
cv2.imshow('contours_result', image_copy)
cv2.waitKey(0)
四、轮廓的常用属性与操作
1. 轮廓面积与周长
- 轮廓面积:使用
cv2.contourArea()
计算 - 轮廓周长:使用
cv2.arcLength()
计算(参数closed=True
表示闭合轮廓)
# 计算第一个轮廓的面积
area_0 = cv2.contourArea(contours[0])
print("第一个轮廓的面积:", area_0)# 计算第一个轮廓的周长
length = cv2.arcLength(contours[0], closed=True)
print("第一个轮廓的周长:", length)
第一个轮廓的面积: 50716.5
第一个轮廓的周长: 952.4377244710922
2. 轮廓筛选与排序
可以根据轮廓面积等属性筛选特定轮廓,或对轮廓进行排序:
# 筛选面积大于 10000 的轮廓
large_contours = []
for cnt in contours:if cv2.contourArea(cnt) > 10000:large_contours.append(cnt)# 绘制筛选后的轮廓
image_copy = phone.copy()
cv2.drawContours(image_copy, large_contours, -1, (0,255,0), 3)
cv2.imshow('contours_larger_10000', image_copy)
cv2.waitKey(0)# 按面积降序排序,取最大面积的轮廓
largest_cnt = sorted(contours, key=cv2.contourArea, reverse=True)[0]
image_copy = phone.copy()
cv2.drawContours(image_copy, [largest_cnt], -1, (0,255,0), 3)
cv2.imshow('largest_contour', image_copy)
cv2.waitKey(0)
3. 轮廓的外接形状
可以计算轮廓的外接圆和最小外接矩形:
# 以外接圆为例(选取第三个轮廓)
cnt = contours[2]
# 计算外接圆
(x, y), r = cv2.minEnclosingCircle(cnt)
# 绘制外接圆
phone_circle = cv2.circle(phone, (int(x), int(y)), int(r), (0,255,0), 2)
cv2.imshow('contour_circle', phone_circle)
cv2.waitKey(0)# 计算最小外接矩形
x, y, w, h = cv2.boundingRect(cnt)
# 绘制矩形
phone_rect = cv2.rectangle(phone, (x, y), (x+w, y+h), (0,255,0), 2)
cv2.imshow('contour_rectangle', phone_rect)
cv2.waitKey(0)
4. 轮廓近似
使用 cv2.approxPolyDP()
函数可以对轮廓进行近似处理,简化轮廓形状:
# 函数语法
# approx = cv2.approxPolyDP(curve, epsilon, closed)# 计算近似精度(取轮廓周长的 0.01 倍)
epsilon = 0.01 * cv2.arcLength(contours[0], True)
# 对第一个轮廓进行近似
approx = cv2.approxPolyDP(contours[0], epsilon, True)# 对比原始轮廓与近似轮廓的点数量
print("原始轮廓点数量:", contours[0].shape[0])
print("近似轮廓点数量:", approx.shape[0])# 绘制近似轮廓
phone_new = phone.copy()
cv2.drawContours(phone_new, [approx], -1, (0,255,0), 3)
cv2.imshow('contour_approx', phone_new)
cv2.waitKey(0)
原始轮廓点数量: 235
近似轮廓点数量: 8
其中,epsilon
参数决定了近似精度:值越小,近似结果越接近原始轮廓;值越大,轮廓越简化。
五、总结
本文详细介绍了 OpenCV 中轮廓检测的核心技术,包括轮廓检测的预处理步骤、cv2.findContours()
函数的使用、轮廓绘制方法以及轮廓的各种属性计算与操作(面积、周长、筛选、排序、外接形状、轮廓近似等)。
轮廓检测在目标识别、图像分割、物体测量等领域有着广泛的应用,掌握这些基础操作是进行更复杂计算机视觉任务的前提。实际应用中,需要根据具体场景选择合适的轮廓检索模式和近似方法,以达到最佳的检测效果。