【OpenCV 轮廓检测与轮廓筛选】
在OpenCV中,轮廓检测和轮廓筛选是图像处理中常用的技术,用于识别和分析图像中物体的形状。以下是详细的分步说明:
一、轮廓检测(Contour Detection)
1. 预处理:生成二值图像
轮廓检测通常在二值图像上进行,因此需要将原图转换为灰度图并进行阈值处理或边缘检测。
import cv2
import numpy as np
# 读取图像
image = cv2.imread('object.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 方法1:阈值处理
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 方法2:Canny边缘检测
edges = cv2.Canny(gray, 50, 150)
2. 调用cv2.findContours()
检测轮廓
该函数返回轮廓的坐标点和层级关系。
# OpenCV 4.x版本:返回contours, hierarchy
contours, hierarchy = cv2.findContours(
binary,
mode=cv2.RETR_EXTERNAL, # 检索模式:仅外部轮廓
method=cv2.CHAIN_APPROX_SIMPLE # 轮廓近似方法:压缩水平、垂直和对角线段
)
- 参数说明:
mode
:轮廓检索模式:cv2.RETR_EXTERNAL
:仅检测外部轮廓。cv2.RETR_TREE
:检测所有轮廓并建立层级树。
method
:轮廓近似方法:cv2.CHAIN_APPROX_SIMPLE
:压缩冗余点,节省内存。cv2.CHAIN_APPROX_NONE
:保留所有轮廓点。
二、轮廓筛选(Contour Filtering)
1. 基于面积筛选
过滤掉面积过小或过大的轮廓。
filtered_contours = []
for cnt in contours:
area = cv2.contourArea(cnt)
if 1000 < area < 50000: # 仅保留面积在1000到50000之间的轮廓
filtered_contours.append(cnt)
2. 基于周长或长宽比
通过外接矩形的长宽比筛选特定形状的轮廓。
for cnt in contours:
x, y, w, h = cv2.boundingRect(cnt)
aspect_ratio = w / h # 长宽比
if 0.8 < aspect_ratio < 1.2: # 近似正方形的轮廓
filtered_contours.append(cnt)
3. 基于形状复杂度
使用多边形近似判断轮廓是否为简单几何形状。
for cnt in contours:
epsilon = 0.02 * cv2.arcLength(cnt, True) # 近似精度(周长2%)
approx = cv2.approxPolyDP(cnt, epsilon, True)
if len(approx) == 4: # 四边形(如矩形)
filtered_contours.append(approx)
4. 基于凸性检测
筛选凸形轮廓。
for cnt in contours:
if cv2.isContourConvex(cnt):
filtered_contours.append(cnt)
三、可视化与输出
1. 绘制筛选后的轮廓
# 在原图上绘制轮廓
output = cv2.drawContours(
image,
filtered_contours,
contourIdx=-1, # -1表示绘制所有轮廓
color=(0, 255, 0), # 绿色
thickness=2
)
cv2.imshow('Filtered Contours', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
2. 提取轮廓坐标
for i, cnt in enumerate(filtered_contours):
print(f"Contour {i} coordinates: {cnt.squeeze()}") # 去除冗余维度
四、常见问题与优化
1. 噪声干扰
- 解决方法:预处理时使用高斯模糊或形态学操作(开运算/闭运算)。
blurred = cv2.GaussianBlur(gray, (5, 5), 0) kernel = np.ones((3, 3), np.uint8) cleaned = cv2.morphologyEx(blurred, cv2.MORPH_CLOSE, kernel)
2. 轮廓断裂
- 解决方法:膨胀操作连接边缘。
dilated = cv2.dilate(edges, kernel, iterations=2)
3. 层级结构处理
- 场景:需区分嵌套轮廓(如字母“O”的内外轮廓)。
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # hierarchy结构:[Next, Previous, First_Child, Parent]
五、完整代码示例
import cv2
import numpy as np
# 1. 读取图像并预处理
image = cv2.imread('objects.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 2. 检测轮廓
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 3. 筛选轮廓(面积 + 形状)
filtered = []
for cnt in contours:
area = cv2.contourArea(cnt)
if area < 1000:
continue
approx = cv2.approxPolyDP(cnt, 0.02*cv2.arcLength(cnt, True), True)
if len(approx) == 4: # 筛选四边形
x, y, w, h = cv2.boundingRect(cnt)
if 0.8 < w/h < 1.2: # 长宽比接近1
filtered.append(cnt)
# 4. 绘制结果
output = cv2.drawContours(image, filtered, -1, (0, 255, 0), 2)
cv2.imshow('Result', output)
cv2.waitKey(0)
六、应用场景
- 目标检测:识别图像中的特定物体(如文档、工业零件)。
- OCR预处理:定位文本区域。
- 医学图像分析:分割细胞或器官轮廓。
- 机器人导航:识别障碍物边界。
通过灵活组合轮廓特征(面积、形状、凸性等),可以高效筛选出符合需求的轮廓,为后续处理提供基础。