一、轮廓检测
轮廓定义:图像中具有相同颜色 / 灰度的连续像素点连接形成的闭合曲线,代表前景与背景的边界,与边缘(单像素灰度突变)不同,轮廓更强调整体外形与连通性。
cv2.findContours是 OpenCV 用于从二值图像中提取轮廓的函数,其核心作用是扫描二值图像的像素,追踪连续的边界点并组织成轮廓集合,同时可返回轮廓间的层级关系(如嵌套、并列)
cv2.findContours(image, mode, method)
参数:
image:必须是单通道二值图(前景白色 255,背景黑色 0),若输入彩色 / 灰度图需先二值化
mode:轮廓检索模式
1.cv2.RETR_EXTERNAL:只提取最外层轮廓(忽略嵌套轮廓),适合只关注主体的场景(如检测单个物体)
2.cv2.RETR_LIST:提取所有轮廓,不建立层级关系(最简洁)
3.cv2.RETR_CCOMP:提取所有轮廓,建立两层层级(外层 + 内层)
4.cv2.RETR_TREE:提取所有轮廓,建立完整层级树(最常用,可区分嵌套 / 并列轮廓)
method:轮廓逼近方法
1.cv2.CHAIN_APPROX_NONE:保留所有轮廓点(每个点都存储,数据量大)
2.cv2.CHAIN_APPROX_SIMPLE:压缩水平 / 垂直 / 对角线方向的冗余点(如矩形只存 4 个顶点,最常用)
代码:
phone=cv2.imread('phone.png')#读取原图 phone_gray=cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)#灰度图的处理 cv2.imshow('phone_b',phone_gray) cv2.waitKey(0) #phone_gray=cv2.imread('phone.png',b)#读取灰度图 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_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) contours = cv2.findContours(phone_binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)[-2] # 通用 # print(hierarchy) print(len(contours))1.通过cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)将图像变成灰度图
2.通过cv2.threshold将灰度值大于 120 的像素设为 255(白色,前景),小于等于 120 的像素设为 0(黑色,背景),最终得到一张黑白二值图。
3.最后用cv2.findContours对二值图像phone_binary提取所有轮廓(含层级)、保留所有轮廓点,最终只取返回结果中的[轮廓列表]
二、轮廓绘制
函数cv2.drawContours(image, contours,contourIdx,color, thickness=None,
LineType=None,hierarchy=None,maxLevel=None,offset=None)
参数含义如下:
image:要在其上绘制轮廊的输入图像。
contours:轮廊列表,通常由cv2.findContours(函数返回。
contourIdx:要绘制的轮序的索引。如果为负数,则绘制所有轮廓。-1
color:轮廓的颜色,以BGR格式表示。例如,(0,255,0)表示绿色。
thickness:轮廓线的粗细。默认值为1。
lineType:轮廊线的类型。默认值为cv2.LINE_8。
hierarchy:轮廓层次结构。通常由cv2.findContours(函数返回。
maxLevel:绘制的最大轮廊层级。默认值为None,表示绘制所有层级。
offset:轮廓点的偏移量。默认值为None。
代码:
image_copy = phone.copy() cv2.drawContours(image=image_copy,contours=contours,contourIdx=6,color=(255,255,0),thickness=3) cv2.imshow('Contours_show',image_copy) cv2.waitKey(0)通过drawContours方法在图像的复制本上绘制轮廓用上面轮廓检测得到的contours轮廓列表
得到的图像:
三、轮廓特征
1.轮廓面积
cv2.contourArea()用于计算单个轮廓所包围的像素面积,面积值反映了轮廓对应的物体大小,是筛选有效轮廓、分析形状的基础。
area = cv2.contourArea(contour, oriented=False)
contour:顶点构成的二维向量组(如轮廓列表contours中的一个轮廓)
oriented:默认为False:返回绝对值面积
2.轮廓周长
cv2.arcLength()用于计算轮廓的弧长 / 周长,对于闭合轮廓返回周长,对于非闭合轮廓返回弧长,是判断轮廓形状、计算圆形度等特征的关键参数。
length = cv2.arcLength(contour, closed)
contour:单个轮廓(来自cv2.findContours返回的contours列表元素)
closed:True:认为轮廓是闭合的(首尾相连),计算完整周长;False:认为轮廓是开放的(首尾不连),计算从起点到终点的弧长
3.轮廓外接圆
cv2.minEnclosingCircle()用于计算单个轮廓的最小外接圆(能完全包围轮廓的最小圆形),返回圆心坐标和半径。
(x_center, y_center), radius = cv2.minEnclosingCircle(contour)
contour:单个轮廓(来自cv2.findContours返回的contours列表元素)
(x_center, y_center):最小外接圆的圆心坐标
radius:最小外接圆的半径
4.轮廓外接矩形
x,y,w,h=cv2.boundingRect(cnt)计算轮廓的最小外接矩形
x,y:是轮廓的最小外接矩形的左上角
w,h:是矩形的宽和高
四、轮廓近似
approx = cv2.approxPolyDP(curve,epsilon,closed)
参数说明:
curve:输入轮廓。
epsilon:近似精度,即两个轮廓之间最大的欧式距离。该参数越小,得到的近似结果越接近实际轮廓:反之,得到的近似结果会更加粗略。
closed:布尔类型的参数,表示是否封闭轮廓。如果是True,表示输入轮廓是封闭的,近似结果也会是封闭的:否则表示输入轮廓不是封闭的,
返回值:approx:近似结果,是一个ndarray数组,为1个近似后的轮廓,包含了被近似出来的轮廓上的点的坐标
代码:
phone = cv2.imread('phone.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.01 * cv2.arcLength(contours[0],True) #设置近似精度.[h要<e;ε越小,点越多,越精确】 approx=cv2.approxPolyDP(contours[0],epsilon,True)#对轮廓进行近似 print(contours[1].shape) print(approx.shape) phone_new = phone.copy() image_contours=cv2.drawContours(phone_new,[approx],contourIdx=-1,color=(0,255,0),thickness=3)#绘制轮廓 cv2.imshow('phone',phone) cv2.waitKey(0) cv2.imshow('image_contours',image_contours) cv2.waitKey(0)得到的图像: