目录
[1 、轮廓检测](#1 、轮廓检测)
[1.1 轮廓与边缘的区别](#1.1 轮廓与边缘的区别)
[1.2 核心 API](#1.2 核心 API)
[cv2.findContours () 查找轮廓](#cv2.findContours () 查找轮廓)
[cv2.drawContours () 绘制轮廓](#cv2.drawContours () 绘制轮廓)
[1.3 轮廓检测基础代码](#1.3 轮廓检测基础代码)
[1.轮廓面积 contourArea](#1.轮廓面积 contourArea)
[2.轮廓周长 arcLength](#2.轮廓周长 arcLength)
[3.外接矩形 boundingRect(正外接矩形,不旋转)](#3.外接矩形 boundingRect(正外接矩形,不旋转))
[4.最小外接旋转矩形 minAreaRect](#4.最小外接旋转矩形 minAreaRect)
[5.轮廓重心(矩 Moments)](#5.轮廓重心(矩 Moments))
[3.1 原理](#3.1 原理)
[3.2 API](#3.2 API)
[3.3 完整综合代码](#3.3 完整综合代码)
前言
承接第 8 章边缘检测。边缘检测只能得到零散的边界像素,轮廓检测可以把同一物体的边界像素组合成一条完整闭合轮廓,常用于物体计数、形状识别、目标分割,是传统计算机视觉高频模块。
1 、轮廓检测
1.1 轮廓与边缘的区别
-
边缘:图像灰度发生突变的像素点,线条零散,不一定闭合。
-
轮廓 :经过算法分组之后,属于同一个物体的闭合边界点集合,可以做后续计算。
重要前提:
cv2.findContours()输入优先使用二值图像 ,黑色为背景,白色为待检测目标。 标准处理流水线:彩色图 → 灰度图 → 二值化threshold→ 查找轮廓。
1.2 核心 API
cv2.findContours () 查找轮廓
python
contours, hierarchy = cv2.findContours(binary_img, mode, method)
-
contours:轮廓列表,存储图像中所有检测到的轮廓。整体为元组嵌套列表结构,每个子列表对应一条独立轮廓,由一组物体边界的(x,y)坐标点组成,可单独提取、处理单条轮廓。 -
hierarchy:轮廓层级,用于处理嵌套轮廓(物体内部存在孔洞)。
检索模式 mode
-
cv2.RETR_EXTERNAL:只提取最外层轮廓,忽略内部孔洞,日常最常用。 -
cv2.RETR_TREE:输出完整的嵌套层级关系,处理孔洞、内外轮廓。
轮廓点存储方式 method
-
cv2.CHAIN_APPROX_SIMPLE:压缩轮廓点,去掉重复冗余点,节省内存,推荐使用。 -
cv2.CHAIN_APPROX_NONE:保存边界上全部像素点,点数量大。
cv2.drawContours () 绘制轮廓
python
cv2.drawContours(dst_img, contours, index, color, thickness)
-
dst_img:绘制轮廓的目标图像,必须传入原图副本,避免修改原始图像。 -
contours:需要绘制的轮廓列表,为findContours检测得到的轮廓数组。 -
index:轮廓索引,-1 代表绘制所有轮廓;传入具体数字(如0、1)仅绘制对应序号的单条轮廓。 -
color:轮廓绘制颜色,遵循 OpenCV 的 BGR 通道格式,例如(0,0,255)为红色、(0,255,0)为绿色。 -
thickness:轮廓线条宽度,单位为像素;设置为 -1 可填充整个轮廓内部区域
1.3 轮廓检测基础代码
python
import cv2
读取原图
phone = cv2.imread(r'D:\pythoncode2\bigdata_ai40\Image\phone.png')
转换灰度图
phone_gray = cv2.cvtColor(phone, cv2.COLOR_BGR2GRAY)
cv2.imshow('phone_gray', phone_gray)
cv2.waitKey(0)
二值化处理:分割前景与背景,生成黑白二值图
ret, phone_binary = cv2.threshold(phone_gray, 127, 255, cv2.THRESH_BINARY)
cv2.imshow('phone_binary', phone_binary)
cv2.waitKey(0)
查找轮廓
[-2] 兼容所有OpenCV版本,稳定获取轮廓列表
RETR_TREE:提取完整层级轮廓(包含内部孔洞)
CHAIN_APPROX_NONE:保留轮廓全部像素点
contours = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2]
print(f"检测到轮廓数量:{len(contours)}")
绘制所有轮廓
img_copy = phone.copy()
cv2.drawContours(image=img_copy, contours=contours, contourIdx=-1, color=(0, 0, 255), thickness=3)
cv2.imshow('phone_contour', img_copy)
cv2.waitKey(0)
释放所有窗口
cv2.destroyAllWindows()

2、轮廓特征
拿到单条轮廓 cnt = contoursi,可以计算物体各类几何特征,用于筛选目标物体。
1.轮廓面积 contourArea
python
area = cv2.contourArea(cnt)
作用:过滤噪声小轮廓,设置面积阈值,把过小干扰轮廓剔除。
2.轮廓周长 arcLength
python
peri = cv2.arcLength(cnt, closed=True)
closed=True 代表轮廓是闭合图形;周长是轮廓近似的重要输入参数。
3.外接矩形 boundingRect(正外接矩形,不旋转)
python
x, y, w, h = cv2.boundingRect(cnt)
- x,y:矩形左上角坐标;w,h:宽、高。
可以画矩形:cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2)
4.最小外接旋转矩形 minAreaRect
python
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.intp(box)
cv2.drawContours(img, [box], 0, (255, 0, 0), 2)
可以得到旋转角度,适合倾斜物体。
5.轮廓重心(矩 Moments)
python
M = cv2.moments(cnt)
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])
获取物体中心点坐标。
使用场景:通过面积、宽高比筛选,只保留我们感兴趣的物体轮廓。
3、轮廓近似
3.1 原理
原始轮廓包含大量点,图像噪声会带来很多毛刺、抖动。
轮廓近似 approxPolyDP 使用道格拉斯‑普克算法,用少量顶点多边形去拟合原始复杂轮廓。
3.2 API
python
approx = cv2.approxPolyDP(curve, epsilon, closed)
- curve:输入单条轮廓,不能直接传入全部 contours 列表。
- epsilon:近似精度,最核心超参数,通常取轮廓周长的比例:
epsilon = 0.04 * cv2.arcLength(cnt, True)
- epsilon 越大:顶点越少,轮廓越粗糙;
- epsilon 越小:顶点越多,越贴近原始轮廓。
- closed=True:表示处理闭合轮廓。
|-----------------------|
| 根据返回approx顶点数量,做形状识别: |
- 3 个顶点 → 三角形
- 4 个顶点 → 矩形、正方形
- 大量顶点 → 圆形或者不规则图形
3.3 完整综合代码
python
import cv2
import numpy as np
读取图像
img = cv2.imread(r'D:\pythoncode2\bigdata_ai40\Image\shape.png')
origin_img = img.copy()
图像预处理:灰度转换 + 二值化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
查找外层轮廓,兼容所有OpenCV版本
contours = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
绘制原始完整轮廓
cv2.drawContours(origin_img, contours, -1, (0, 255, 0), 2)
遍历所有轮廓,计算特征、绘制矩形并执行轮廓近似
for cnt in contours:
# 1. 计算轮廓面积,过滤微小噪声轮廓
area = cv2.contourArea(cnt)
if area < 50:
continue
# 2. 计算闭合轮廓周长
peri = cv2.arcLength(cnt, closed=True)
# 3. 轮廓近似:通过周长比例设置精度
epsilon = 0.04 * peri
approx = cv2.approxPolyDP(cnt, epsilon, closed=True)
# 绘制近似后的多边形轮廓
cv2.drawContours(img, [approx], -1, (255, 0, 0), 2)
# 4. 绘制正外接矩形(不旋转)
x, y, w, h = cv2.boundingRect(approx)
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 255), 2)
# 5. 绘制最小外接旋转矩形(适配倾斜物体)
min_rect = cv2.minAreaRect(cnt)
min_box = cv2.boxPoints(min_rect)
min_box = np.intp(min_box)
cv2.drawContours(img, [min_box], 0, (255, 255, 0), 2)
# 识别轮廓顶点数量并标注
point_num = len(approx)
cv2.putText(img, f"pts:{point_num}", (x, y-8),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
展示结果
cv2.imshow("raw_contour", origin_img)
cv2.imshow("approx_feature_result", img)
cv2.waitKey(0)
释放所有窗口
cv2.destroyAllWindows()
4、本章小结
-
轮廓是闭合物体点集,由二值图像提取,区别于零散边缘。
-
轮廓特征包含面积、周长、外接矩形、重心,用于筛选目标物体。
-
轮廓近似
approxPolyDP依靠 epsilon 控制精度,依靠顶点数目实现简单形状识别。 -
典型场景:零件检测、答题卡识别、图形分类、物体计数。
