一、什么是轮廓
轮廓是图像中连续且闭合的相同灰度值像素边界,是区别于边缘检测的关键概念
边缘检测仅提取灰度突变的离散像素点,而轮廓强调闭合性与整体性,能完整描述物体的形状边界。
OpenCV 处理轮廓有一个硬性前提 ------输入图像必须是二值化图像(黑白两色)。因为二值化通过阈值分割将目标物体与背景完全分离,消除颜色、灰度渐变的干扰,让计算机能精准识别物体边界。
因此,轮廓处理的标准流程为:图像读取→灰度转换→二值化→轮廓检测→特征分析→轮廓近似,后续所有操作均围绕提取的轮廓集合展开。
二、轮廓检测
代码如下:
python
import cv2
#读取原始图像
phone =cv2.imread(r"C:\Users\LEGION\Desktop\3aabc73ccef88454844220cca0716c09.png")
#灰度图的处理
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
cv2.imshow('phone_b',phone_gray)
cv2.waitKey(0)
#二值化处理:固定阈值分割,实现黑白分离
# 阈值120:像素>120设为255(白),≤120设为0(黑)
ret, phone_binary = cv2.threshold(phone_gray, 120, 255,cv2.THRESH_BINARY)#阈值处理为三值
cv2.imshow( 'phone_binary',phone_binary)
cv2.waitKey(0)
# 提取轮廓:检索所有轮廓并保存全部像素点
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
print(len(contours))
#绘制所有轮廓并展示
image_copy = phone.copy()
cv2.drawContours(image=image_copy, contours=contours, contourIdx=-1,color=(0,255,0),thickness=2)
cv2.imshow('Contours_show',image_copy)
cv2.waitKey(0)
注释:
二值化阈值:120 为经验值,可根据图像明暗调整 ------ 阈值过小易引入背景噪点,阈值过大易丢失物体边缘;
contourIdx=-1,
-1表示绘制所有轮廓 color=(0,255,0),
thickness=2 轮廓线宽度
运行结果:

三、轮廓特征
提取轮廓后,OpenCV 可通过内置函数计算轮廓的面积、周长等几何特征,这些特征是筛选目标轮廓、实现精准定位的核心依据。
代码如下:(接上文图片)
1.核心特征计算
轮廓面积
cv2.contourArea(contour[, oriented]) 是 OpenCV 中专门用于计算轮廓面积的函数,它能根据轮廓的顶点坐标,精准计算出该轮廓所包围区域的面积,返回值是一个浮点数(面积数值)。
contour: 顶点构成的二维向量组(如轮廓列表contours中的一个轮廓)
oriented = 0: 定向区域标志,默认值为 False,返回面积的绝对值,Ture 时则根据轮廓方向返回带符号的数值
retval:计算出的轮廓面积,浮点数类型。
python
area_0 = cv2.contourArea(contours[0]) #轮廓面积
print(area_0)
area_1 = cv2.contourArea(contours[1])
print(area_1)
运行结果:

轮廓周长
arcLength(InputArray curve, bool closed) 用于计算轮廓的周长或曲线的长度
curve, 输入的二维点集(轮廓顶点),可以是 vector 或 Mat 类型。
closed,用于指示曲线是否闭合,closed=True表示轮廓闭合
python
length = cv2.arcLength(contours[0],closed=True)
print(length)
运行结果:

2.根据面积显示特定轮廓
python
#按面积阈值筛选(仅保留面积>10000的轮廓)
a_list=[]
for i in contours:
if cv2.contourArea(i)>10000:
a_list.append(i)
#绘制筛选后的轮廓
image_copy = phone.copy()
image_copy = cv2.drawContours(image=image_copy, contours=a_list, contourIdx=-1,color=(0,255,0),thickness=3)
cv2.imshow( 'Contours_show_10000', image_copy)
cv2.waitKey(0)
运行结果:

3.按面积排序提取最大轮廓
python
sortcnt = sorted(contours, key=cv2.contourArea, reverse=True)[0] # 选取最大面积的轮廓
image_contours = cv2.drawContours(image_copy, [sortcnt],contourIdx=-1,color=(0,0,255),thickness=3)#绘制轮廓
cv2.imshow('image_contours',image_contours)
cv2.waitKey(0)
运行结果:

4.轮廓几何拟合:外接圆与外接矩形
外接圆:
python
cnt = contours[6]
(x,y),r = cv2.minEnclosingCircle(cnt)#计算轮廓的外接圆
phone_circle = cv2.circle(phone, (int(x),int(y)),int(r),(0,255,0), 2)#绘制外接圆的方法
cv2.imshow('phone_circle',phone_circle)
cv2.waitKey(0)
运行结果:

外接矩形:
python
cnt = contours[6]
x,y,w,h = cv2.boundingRect(cnt)#计算轮廓的最小外接矩形
phone_rectangle = cv2.rectangle(phone, (x,y), (x+w,y+h), (0,255,0), 2) #在图像上绘制矩形
cv2.imshow( 'phone_rectangle',phone_rectangle)
cv2.waitKey(0)
运行结果:

四、轮廓近似
原始轮廓由大量像素点组成(可能上千个),轮廓近似(多边形逼近)通过cv2.approxPolyDP()用更少的点拟合轮廓,在不丢失核心形状的前提下简化数据,提升处理效率。
代码如下:
python
phone = cv2.imread(r"C:\Users\LEGION\Desktop\3aabc73ccef88454844220cca0716c09.png")
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY) #转换为灰度图
ret,phone_thresh = cv2.threshold(phone_gray, 120, 255,cv2.THRESH_BINARY) #二值化
# image, contours, hierarchy = cv2.findContours(phone_thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)#获取轮廓
contours=cv2.findContours(phone_thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)[-2]
epsilon = 0.001 * cv2.arcLength(contours[0], True) #设置近似精度 【h要<ε;ε越小,点越多,越精确】
approx = cv2.approxPolyDP(contours[0], epsilon, True) #对轮廓进行近似
print(contours[0].shape)
print(approx.shape)
注释:
近似精度 ε :epsilon = 0.001 * cv2.arcLength(contours[0], True)是轮廓近似的核心参数,ε 越小,近似轮廓越接近原轮廓,点数量越多;ε 越大,轮廓简化越明显,可能丢失形状特征;
cv2.approxPolyDP() :第三个参数True保证近似后的轮廓仍是闭合的,这是形状分析的必要条件。
运行结果:
