核心内容摘要
如何选择?2025年最值得尝试的Flipper Zero固件方案
本文旨在帮助掌握 OpenCV-Python 中图像轮廓的查找与绘制方法轮廓是图像中连续的、具有相同像素值的边界曲线是图像分割、目标检测、形状分析的核心工具。
OpenCV 中通过cv
findContours()查找轮廓cv
drawContours()绘制轮廓核心流程是图像预处理二值化→ 查找轮廓 → 绘制轮廓下面会从原理、完整流程、API 详解、实战示例和高级应用逐步讲解内容贴合实际开发需求。
轮廓的核心概念轮廓是二值图像中白色前景的边界黑色为背景因此查找轮廓前必须将图像转为二值图灰度→阈值分割 / 边缘检测轮廓与边缘的区别边缘是离散的像素点轮廓是连续的闭合曲线且轮廓只针对前景区域轮廓的层级图像中轮廓可能存在嵌套关系如大矩形内有小矩形OpenCV 会记录轮廓的父子层级关系便于筛选内外轮廓。
核心 API 详解
查找轮廓cv
findContours()函数原型OpenCV4 版本返回值简化为 2 个轮廓和层级contours, hierarchy cv
findContours(image, mode, method)关键参数参数作用常用值image输入图像必须是二值图uint8 类型黑白建议对原二值图做复制函数会修改原图mode轮廓检索模式控制查找的轮廓范围和层级cv
RETR_EXTERNAL仅检索最外层轮廓最常用cv
RETR_LIST检索所有轮廓不建立层级cv
RETR_CCOMP检索所有轮廓建立两层层级外 / 内cv
RETR_TREE检索所有轮廓建立完整的树形层级method轮廓逼近方法压缩轮廓点减少冗余cv
CHAIN_APPROX_NONE保存所有轮廓点精度最高数据量大cv
CHAIN_APPROX_SIMPLE压缩水平 / 垂直 / 对角线仅保存端点如矩形只存 4 个角点最常用返回值contours轮廓列表每个轮廓是N×1×2的 NumPy 数组存储轮廓的 (x,y) 坐标点hierarchy层级数组形状为1×N×4每个轮廓对应 4 个值[next, prev, child, parent]分别表示「下一个轮廓、上一个轮廓、子轮廓、父轮廓」无对应轮廓时为 - 1。
绘制轮廓cv
drawContours()函数原型img cv
drawContours(image, contours, contourIdx, color, thicknessNone, lineTypeNone, hierarchyNone, maxLevelNone, offsetNone)关键参数参数作用常用值image绘制的目标图像建议用彩色图方便看轮廓直接修改原图可提前复制contours待绘制的轮廓列表即cv
findContours()的返回值contourIdx绘制的轮廓索引-1绘制所有轮廓具体数字如
1绘制指定索引的轮廓color轮廓颜色BGR 格式如(0,255,
绿色、(0,0,
红色thickness轮廓线宽正数线宽如
填充轮廓内部绘制实心形状maxLevel绘制的轮廓层级配合hierarchy使用0仅绘制当前轮廓1绘制当前 子轮廓
查找并绘制轮廓的标准流程所有轮廓操作的基础是高质量的二值图预处理不到位会导致轮廓检测混乱标准步骤如下读取图像转为灰度图cv
cvtColor()图像预处理可选去噪cv
GaussianBlur()避免噪声被检测为轮廓二值化cv
threshold()/cv
adaptiveThreshold()将图像转为黑白突出前景可选形态学运算cv
dilate()/cv
erode()膨胀填充前景孔洞腐蚀去除微小噪声查找轮廓cv
findContours()复制二值图避免被修改绘制轮廓cv
drawContours()用彩色图绘制方便可视化显示 / 保存结果。
基础实现代码最常用场景检测外轮廓并绘制import cv2 import numpy as np import matplotlib.pyplot as plt #
读取图像并转灰度 img cv
imread(shape.jpg) # 读取彩色图用于后续绘制轮廓 gray cv
cvtColor(img, cv
COLOR_BGR2GRAY) cv
imshow(Gray, gray) #
预处理高斯去噪 二值化关键让前景和背景分离 blur cv
GaussianBlur(gray, (3,
,
# 去噪避免噪声干扰轮廓检测 # 二值化大于127设为255白前景小于设为0黑背景THRESH_BINARY_INV为反向 ret, binary cv
threshold(blur, 127, 255, cv
THRESH_BINARY) cv
imshow(Binary, binary) #
查找轮廓仅找外轮廓压缩轮廓点最常用参数组合 # 注意传入binary的复制避免函数修改原二值图 contours, hierarchy cv
findContours(binary.copy(), cv
RETR_EXTERNAL, cv
CHAIN_APPROX_SIMPLE) print(f检测到的轮廓数量{len(contours)}) #
绘制轮廓在彩色原图的复制上绘制绿色线宽2绘制所有轮廓 img_contour img.copy() cv
drawContours(img_contour, contours, -1, (0, 255,
,
#
显示结果 cv
imshow(Contour, img_contour) cv
waitKey(
cv
destroyAllWindows()
关键优化形态学运算优化二值图如果二值图存在前景孔洞或微小噪声点会导致检测到多余轮廓或轮廓不闭合此时用形态学膨胀 / 闭运算优化# 二值化后添加形态学运算 kernel cv
getStructuringElement(cv
MORPH_RECT, (3,
) # 闭运算膨胀→腐蚀填充前景内部的小孔洞 binary_close cv
morphologyEx(binary, cv
MORPH_CLOSE, kernel) # 膨胀让前景轮廓更连续可选根据图像调整 # binary_dilate cv
dilate(binary_close, kernel, iterations
# 再查找轮廓 contours, hierarchy cv
findContours(binary_close.copy(), cv
RETR_EXTERNAL, cv
CHAIN_APPROX_SIMPLE)
实战常见需求
绘制单个轮廓 填充轮廓内部img_contour img.copy() # 绘制第0个轮廓红色线宽3 cv
drawContours(img_contour, contours, 0, (0, 0,
,
# 绘制第1个轮廓蓝色填充内部thickness-1 cv
drawContours(img_contour, contours, 1, (255, 0,
, -
cv
imshow(Single Filled Contour, img_contour)
筛选轮廓按面积 / 周长实际开发中噪声会被检测为小轮廓可通过轮廓面积cv
contourArea()或轮廓周长cv
arcLength()筛选有效轮廓img_filter img.copy() valid_contours [] # 存储有效轮廓 for cnt in contours: # 计算轮廓面积 area cv
contourArea(cnt) # 计算轮廓周长True表示轮廓闭合 perimeter cv
arcLength(cnt, True) # 筛选面积大于100的轮廓阈值根据图像调整 if area 100: valid_contours.append(cnt) # 在轮廓旁绘制面积值 # 获取轮廓的外接矩形确定文字位置 x, y, w, h cv
boundingRect(cnt) cv
putText(img_filter, fArea:{int(area)}, (x, y-
, cv
FONT_HERSHEY_SIMPLEX,
5, (0,255,
,
# 绘制筛选后的有效轮廓 cv
drawContours(img_filter, valid_contours, -1, (0,255,
,
print(f筛选后的有效轮廓数量{len(valid_contours)}) cv
imshow(Filtered Contour, img_filter)
绘制轮廓的外接矩形 / 外接圆目标定位轮廓的外接矩形 / 外接圆是目标定位的常用手段结合cv
boundingRect()外接矩形、cv
minEnclosingCircle()最小外接圆实现img_outer img.copy() for cnt in valid_contours: # 绘制外接矩形绿色 x, y, w, h cv
boundingRect(cnt) cv
rectangle(img_outer, (x,y), (xw,yh), (0,255,
,
# 绘制最小外接圆红色 (x_c, y_c), r cv
minEnclosingCircle(cnt) center (int(x_c), int(y_c)) radius int(r) cv
circle(img_outer, center, radius, (0,0,
,
cv
imshow(Outer Shape, img_outer)
检测嵌套轮廓绘制内外轮廓使用cv
RETR_TREE检索所有层级轮廓结合hierarchy区分内外轮廓父轮廓parent-1子轮廓parent≥0# 重新查找所有轮廓建立树形层级 contours, hierarchy cv
findContours(binary_close.copy(), cv
RETR_TREE, cv
CHAIN_APPROX_SIMPLE) img_tree img.copy() for i, cnt in enumerate(contours): # 父轮廓索引hierarchy[0][i][3] parent hierarchy[0][i][3] if parent -1: # 无父轮廓 → 外层轮廓绿色 cv
drawContours(img_tree, contours, i, (0,255,
,
else: # 有父轮廓 → 内层轮廓红色 cv
drawContours(img_tree, contours, i, (0,0,
,
cv
imshow(Inner Outer Contour, img_tree)
高级应用轮廓的形状识别通过轮廓的逼近多边形cv
approxPolyDP()判断形状如三角形、矩形、圆形核心原理是用最少的点逼近轮廓点的数量对应形状的边数img_shape img.copy() for cnt in valid_contours: perimeter cv
arcLength(cnt, True) # 轮廓逼近epsilon为周长的
04倍阈值越小逼近越接近原轮廓 epsilon
04 * perimeter approx cv
approxPolyDP(cnt, epsilon, True) # 获取逼近后的顶点数量 vertex_num len(approx) # 判断形状 if vertex_num 3: shape Triangle elif vertex_num 4: # 4个顶点判断是否为正方形长宽比接近1 x, y, w, h cv
boundingRect(approx) ratio w / float(h) shape Square if
95 ratio
05 else Rectangle elif vertex_num 6: shape Circle else: shape Other # 绘制逼近多边形形状文字 cv
drawContours(img_shape, [approx], 0, (0,255,
,
cv
putText(img_shape, shape, (cnt[:,0,0].min(), cnt[:,0,1].min()-
, cv
FONT_HERSHEY_SIMPLEX,
5, (255,0,
,
cv
imshow(Shape Recognition, img_shape)
七、
常见问题与解决方案检测不到轮廓二值图前景 / 背景颠倒改用cv
THRESH_BINARY_INV反向二值化图像有噪声增加高斯去噪或形态学运算轮廓是黑色二值图必须白色为前景黑色为背景。
检测到大量冗余小轮廓按轮廓面积 / 周长筛选或增大形态学腐蚀的核尺寸。
轮廓不闭合用形态学闭运算填充轮廓间隙或调整二值化阈值。
OpenCV3 和 OpenCV4 的 API 差异OpenCV3image, contours, hierarchy cv
findContours(...)多返回一个修改后的图像OpenCV4contours, hierarchy cv
findContours(...)推荐简化返回值。
完整综合示例轮廓检测 筛选 形状识别 绘制import cv2 import numpy as np #
读取图像并预处理 img cv
imread(shape_mix.jpg) if img is None: raise ValueError(图像读取失败请检查路径) gray cv
cvtColor(img, cv
COLOR_BGR2GRAY) blur cv
GaussianBlur(gray, (3,
,
ret, binary cv
threshold(blur, 127, 255, cv
THRESH_BINARY) #
形态学优化二值图 kernel cv
getStructuringElement(cv
MORPH_RECT, (3,
) binary_close cv
morphologyEx(binary, cv
MORPH_CLOSE, kernel) #
查找外轮廓 contours, hierarchy cv
findContours(binary_close.copy(), cv
RETR_EXTERNAL, cv
CHAIN_APPROX_SIMPLE) #
筛选有效轮廓形状识别绘制 img_result img.copy() valid_contours [] for cnt in contours: area cv
contourArea(cnt) if area 50: # 筛选面积大于50的轮廓 valid_contours.append(cnt) # 轮廓逼近 perimeter cv
arcLength(cnt, True) epsilon
04 * perimeter approx cv
approxPolyDP(cnt, epsilon, True) vertex_num len(approx) # 判断形状 if vertex_num 3: shape Triangle color (0, 255,
elif vertex_num 4: x, y, w, h cv
boundingRect(approx) ratio w / float(h) shape Square if
95 ratio
05 else Rectangle color (0, 0,
elif vertex_num 6: shape Circle color (255, 0,
else: shape Other color (128, 128,
# 绘制轮廓外接矩形形状文字 cv
drawContours(img_result, [approx], 0, color,
x, y, w, h cv
boundingRect(cnt) cv
rectangle(img_result, (x, y), (xw, yh), color,
cv
putText(img_result, f{shape}({int(area)}), (x, y-
, cv
FONT_HERSHEY_SIMPLEX,
4, color,
#
显示所有结果 cv
imshow(Original, img) cv
imshow(Binary, binary_close) cv
imshow(Contour Shape Recognition, img_result) print(f原始轮廓数{len(contours)}有效轮廓数{len(valid_contours)}) cv
waitKey(
cv
destroyAllWindows() # 保存结果 cv
imwrite(contour_result.jpg, img_result)
总结OpenCV-Python 查找并绘制轮廓的核心要点预处理是基础灰度→去噪→二值化→形态学优化确保二值图白色前景、黑色背景无噪声和孔洞API 核心参数查找轮廓cv
RETR_EXTERNAL外轮廓cv
CHAIN_APPROX_SIMPLE压缩点是最常用组合绘制轮廓contourIdx-1绘所有轮廓thickness-1填充内部实用技巧用cv
contourArea()/cv
arcLength()筛选有效轮廓排除噪声用cv
boundingRect()/cv
minEnclosingCircle()实现目标定位用cv
approxPolyDP()做轮廓逼近实现形状识别层级轮廓cv
RETR_TREE检索所有嵌套轮廓通过hierarchy区分内外轮廓。
轮廓操作是 OpenCV 图像处理的核心技能广泛应用于目标检测、图像分割、工业检测如瑕疵识别、形状分析等场景掌握上述方法即可应对绝大多数实际开发需求。