文章目录
-
- 一、轮廓的核心概念与基础定义
-
- [1. 轮廓的本质的](#1. 轮廓的本质的)
- [2. 轮廓与边缘的核心区别](#2. 轮廓与边缘的核心区别)
- [3. 轮廓绘制的基础术语定义](#3. 轮廓绘制的基础术语定义)
- 二、轮廓绘制的实操流程与注意事项
-
- [1. 完整实操流程(以Python+OpenCV为例)](#1. 完整实操流程(以Python+OpenCV为例))
-
- (1)环境准备
- (2)图像预处理
- (3) 轮廓点压缩的合理使用 轮廓点压缩的合理使用)
- (4)轮廓特征计算
- (5)轮廓可视化
- [2. 实操注意事项(避坑指南)](#2. 实操注意事项(避坑指南))
- 三、总结与拓展
一、轮廓的核心概念与基础定义
1. 轮廓的本质的
轮廓是目标物体或区域在图像中的封闭边界集合,由一系列连续相连的像素点构成,能够完整勾勒出物体的外部形态和内部结构。与单纯的边缘检测不同,轮廓强调像素的连通性和边界的封闭性,是对物体形状的完整描述,而非孤立的边缘片段。
在机器视觉任务中,轮廓的核心价值在于将图像的像素信息转化为可量化的几何特征(如周长、面积、中心坐标等),为后续的形状分析、目标识别和图像分割提供基础数据支撑。
2. 轮廓与边缘的核心区别
很多初学者容易混淆轮廓和边缘,二者虽有重叠但本质不同,具体区别如下:
| 对比维度 | 轮廓 | 边缘 |
|---|---|---|
| 像素特性 | 连续连通的封闭集合 | 可孤立、不连续的像素点 |
| 核心用途 | 物体形态分析(周长、面积等) | 图像特征提取(区分不同区域) |
| 存在前提 | 必须形成封闭结构 | 只要灰度值突变即可存在 |
| 数据形式 | 完整的边界序列 | 离散的边缘点或边缘线 |
举个直观例子:一张手写数字"8"的二值图,边缘是数字笔画与背景交界处的所有像素点(可能存在断点),而轮廓是能够完整包围"8"外部和内部孔洞的两条封闭边界,通过这两条轮廓可直接计算数字的总面积、外周长、内孔洞面积等关键参数。
3. 轮廓绘制的基础术语定义
在进行轮廓绘制前,需明确以下核心术语,避免后续算法理解出现偏差:
(1)图像与像素相关
- frame(图像框架):一张图像的最上行、最下行、最左列、最右列构成的边界,是图像的天然边界。
- 0-pixel(0像素):灰度值为0的像素,默认作为图像背景填充像素。
- 1-pixel(1像素):灰度值为1的像素,默认作为目标物体的构成像素。
- 像素坐标与灰度值:用(i, j)表示图像中第i行、第j列的像素点,(f_{i,j})表示该像素点的灰度值,整幅图像可表示为像素灰度值的集合(F={f_{i,j}})。
(2)连通域相关
- 连通域(component) :由相邻(通常指8连通或4连通)的同一灰度值像素构成的区域。
- 1-component(1连通域):由1像素组成的连通域,即目标物体所在区域。
- 0-component(0连通域):由0像素组成的连通域,可能是背景或物体内部的孔洞。
- background(背景):包含frame(图像框架)的0连通域,是图像中目标物体的外部环境区域。
- 孔洞(hole):不包含frame的0连通域,是目标物体内部被1像素包围的空白区域(如数字"8"中间的两个空白区域)。
(3)边界相关
- borderpoint(边界点):若一个1像素的8连通区域内存在0像素,则该1像素为边界点。轮廓正是由一系列连续的边界点构成。
- 环绕连通域:在二值图中,若连通域S1中任意像素点沿4方向到达frame的路径上均存在S2的像素,则称S2环绕S1;若S2环绕S1且两者之间存在边界点,则称S2直接环绕S1。
- 外边界与孔边界 :
- 外边界:若0连通域S2直接环绕1连通域S1,则S2与S1之间的边界为外边界(包围目标物体的外部边界)。
- 孔边界:若1连通域S1直接环绕0连通域S2,则S2与S1之间的边界为孔边界(包围物体内部孔洞的边界)。
- 父边界:若0连通域S2直接环绕1连通域S1,1连通域S3直接环绕S2,S1与S2的边界为B1,S2与S3的边界为B2,则B2为B1的父边界;若S2是背景(background),则B1的父边界为frame。
二、轮廓绘制的实操流程与注意事项
1. 完整实操流程(以Python+OpenCV为例)
OpenCV是机器视觉领域常用的开源库,提供了成熟的轮廓检测函数cv2.findContours(),其底层实现基于上述边界跟踪算法。以下是完整的实操流程,从图像预处理到轮廓可视化,一步一步实现轮廓绘制:
(1)环境准备
安装必要的库:
python
pip install opencv-python numpy matplotlib
(2)图像预处理
图像预处理是轮廓绘制的关键前提,直接影响轮廓检测的准确性。常见的预处理步骤包括:
- 读取图像:读取原始图像,若为彩色图需转为灰度图。
- 二值化:将灰度图转为二值图,分离目标与背景。
- 噪声去除:通过形态学操作(如腐蚀、膨胀)去除图像噪声,避免噪声形成虚假轮廓。
代码实现:
python
#导入opencv库
import cv2
#1.读取图片
image_np = cv2.imread('./picture.png')
#复制一份原始图像,用来绘制轮廓
image_contours = image_np.copy()
#2.灰度化
image_gray = cv2.cvtColor(image_np,cv2.COLOR_BGR2GRAY)
#3.二值化
ret,image_binary = cv2.threshold(image_gray,127,255,cv2.THRESH_OTSU+cv2.THRESH_BINARY_INV)
#4.查找轮廓
#contours:存储了所有轮廓点的坐标,比如术后contours[0]就存储了第0个轮廓的点的坐标,contours[1]就存储了第一个轮廓的层级关系
#hierarchy: 存储了对应轮廓的层级关系,hierarchy[0]就存储了第0个轮廓的层级关系
contours,hierarchy = cv2.findContours(image_binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#5.绘制轮廓
cv2.drawContours(image_contours,contours,-1,(0,0,255) )
#6.结果显示
cv2.imshow('image_np',image_np)
cv2.imshow('image_contours', image_contours)
cv2.waitKey(0)```
#### (3)轮廓检测
使用`cv2.findContours()`函数检测轮廓,该函数返回轮廓列表、轮廓层级关系和边界矩形:
```python
# 轮廓检测(cv2.RETR_CCOMP:检测所有轮廓并建立层级关系;cv2.CHAIN_APPROX_SIMPLE:压缩轮廓点)
contours, hierarchy = cv2.findContours(opening, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
# 打印轮廓信息
print(f"检测到的轮廓数量:{len(contours)}")
print(f"轮廓层级关系:{hierarchy}") # hierarchy格式:[Next, Previous, First_Child, Parent]
输出结果为:
注意:图片路径需要你自己导入你设备上的路径


(3) 轮廓点压缩的合理使用
cv2.findContours()函数的method参数用于轮廓点的压缩:
- cv2.CHAIN_APPROX_SIMPLE:压缩轮廓点,仅保留轮廓的关键顶点(如矩形轮廓仅保留 4 个顶点),减少数据量,提高后续处理效率。
- cv2.CHAIN_APPROX_NONE:保留轮廓上的所有像素点,数据量较大,但适合需要高精度轮廓的场景(如微小零件的尺寸测量)。
(4)轮廓特征计算
根据检测到的轮廓,计算关键几何特征:
python
# 遍历所有轮廓,计算特征
contour_features = []
for i, cnt in enumerate(contours):
# 1. 面积
area = cv2.contourArea(cnt)
# 2. 周长(True表示闭合轮廓)
perimeter = cv2.arcLength(cnt, True)
# 3. 外接矩形
x, y, w, h = cv2.boundingRect(cnt)
# 4. 中心坐标(矩)
M = cv2.moments(cnt)
cx = int(M["m10"] / M["m00"]) if M["m00"] != 0 else 0
cy = int(M["m01"] / M["m00"]) if M["m00"] != 0 else 0
# 5. 圆形度
circularity = 4 * np.pi * area / (perimeter ** 2) if perimeter != 0 else 0
contour_features.append({
"轮廓编号": i,
"面积": area,
"周长": perimeter,
"外接矩形(x,y,w,h)": (x, y, w, h),
"中心坐标(cx,cy)": (cx, cy),
"圆形度": circularity
})
# 打印特征结果
for feature in contour_features:
print(f"\n轮廓{feature['轮廓编号']}特征:")
for key, value in feature.items():
print(f"{key}:{value}")
(5)轮廓可视化
将检测到的轮廓绘制在原始图像上,直观展示检测结果:
python
# 绘制轮廓(-1表示填充轮廓内部,0表示仅绘制边界)
img_contour = img.copy()
cv2.drawContours(img_contour, contours, -1, (0, 255, 0), 2) # 绿色绘制轮廓,线宽2
# 绘制中心坐标和轮廓编号
for i, cnt in enumerate(contours):
M = cv2.moments(cnt)
cx = int(M["m10"] / M["m00"]) if M["m00"] != 0 else 0
cy = int(M["m01"] / M["m00"]) if M["m00"] != 0 else 0
cv2.circle(img_contour, (cx, cy), 3, (255, 0, 0), -1) # 蓝色绘制中心点
cv2.putText(img_contour, str(i), (cx+5, cy), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) # 红色标注轮廓编号
# 显示可视化结果
plt.figure(figsize=(8, 6))
plt.imshow(cv2.cvtColor(img_contour, cv2.COLOR_BGR2RGB))
plt.title("轮廓检测结果")
plt.axis("off")
plt.show()
2. 实操注意事项(避坑指南)
(1)图像预处理是关键
- 二值化阈值选择:若阈值过高,会导致目标物体像素丢失,轮廓不完整;若阈值过低,会引入过多背景噪声,形成虚假轮廓。建议使用自适应阈值分割(
cv2.adaptiveThreshold())或大津阈值分割(cv2.THRESH_OTSU),避免手动阈值的主观性。 - 噪声去除:工业图像或手写图像中常存在椒盐噪声,需通过形态学操作(开运算、闭运算)或高斯滤波(
cv2.GaussianBlur())去除噪声,否则噪声会被误检测为小轮廓,影响后续分析。
(2)轮廓层级关系的正确理解
cv2.findContours()函数的mode参数决定了轮廓的层级检测方式,常用的两种模式:
cv2.RETR_EXTERNAL:仅检测最外层轮廓,忽略内部孔边界,适合只需目标物体外轮廓的场景。cv2.RETR_CCOMP:检测所有轮廓并建立两层层级关系(外边界为第一层,孔边界为第二层),适合需要分析物体内部孔洞的场景。
若不理解层级关系,可能会误将孔边界当作独立的目标轮廓,导致特征计算错误。
(3)轮廓点压缩的合理使用
cv2.findContours()函数的method参数用于轮廓点的压缩:
cv2.CHAIN_APPROX_SIMPLE:压缩轮廓点,仅保留轮廓的关键顶点(如矩形轮廓仅保留4个顶点),减少数据量,提高后续处理效率。cv2.CHAIN_APPROX_NONE:保留轮廓上的所有像素点,数据量较大,但适合需要高精度轮廓的场景(如微小零件的尺寸测量)。
根据实际需求选择压缩方式,避免不必要的计算开销。
(4)特征计算的异常处理
在计算轮廓特征时,需避免分母为0的情况:
- 周长为0:可能是孤立的单个像素点,需过滤此类无效轮廓。
- 矩的m00为0:表示轮廓面积为0,是无效轮廓,需跳过中心坐标计算。
(5)多目标轮廓的筛选
若图像中存在多个轮廓,需根据实际需求筛选目标轮廓:
- 按面积筛选:设置面积阈值,过滤掉面积过小的噪声轮廓和面积过大的背景轮廓。
- 按宽高比筛选:根据目标物体的宽高比范围,筛选出符合要求的轮廓(如矩形零件的宽高比通常在1-3之间)。
代码示例(按面积筛选):
python
# 筛选面积在100-10000之间的轮廓
valid_contours = [cnt for cnt in contours if 100 < cv2.contourArea(cnt) < 10000]
print(f"筛选后的有效轮廓数量:{len(valid_contours)}")
三、总结与拓展
图像轮廓绘制是机器视觉的核心技术之一,其本质是通过边界跟踪算法提取目标物体的封闭边界,为形状分析、目标识别和图像分割提供基础。本文从核心概念、作用场景、算法原理、实操流程四个维度,详细解析了轮廓绘制的全流程,关键要点总结如下:
- 轮廓与边缘的核心区别在于连通性和封闭性,轮廓是完整的封闭边界,而边缘可孤立不连续。
- 边界跟踪算法是轮廓绘制的核心,通过光栅扫描检测起始点,结合顺时针/逆时针邻域搜索实现轮廓跟踪。
- 实操中需重视图像预处理,合理选择二值化方法和形态学操作,避免噪声和阈值不当导致的检测误差。
- 轮廓特征计算和可视化是后续应用的基础,需根据实际需求筛选有效轮廓并计算关键参数。