OpenCV轮廓检测全面解析:从基础到高级应用

一、概述

轮廓检测是计算机视觉中的基础技术,用于识别和提取图像中物体的边界。与边缘检测不同,轮廓检测更关注将边缘像素连接成有意义的整体,形成封闭的边界。

轮廓检测的核心价值

  • 物体识别:通过轮廓可以识别图像中的独立物体

  • 形状分析:轮廓包含了物体的形状特征信息

  • 测量计算:基于轮廓可进行面积、周长等测量

  • 图像分割:是许多分割算法的基础步骤

二、OpenCV轮廓检测基础

1.cv2.findContours

2. cv2.drawContours()

3.示例代码

python 复制代码
#查找轮廓的API:image,contours,hierarchy = cv2.findContours(img, mode, method)#
# 参数:img:需要实现轮廓检测的原图

# mode:轮廓的检索模式,主要有四种方式:
#      CV2.RETR_EXTERNAL:只检测外轮廓,所有子轮廓被忽略并
#      CV2.RETR_LIST:检测的轮廓不建立等级关系,所有轮廊属于同一等级
#      CV2.RETR_CCOMP:返回所有的轮廓,只建立两个级的轮。一个对象的外轮为第1级组织结构。
#          而对象内部中空洞的轮廊为第2级组织结构,空洞中的任何对象的轮又是第 1级组织结构。
#      cV2.RETR_TREE:返回所有的轮廓,建立一个完整的组织结构的轮廓。

# method:轮廓的近似方法,主要有以下两种:
#      CV2.CHAIN APPROX NONE:在储所有的轮点。
#      CV2.CHAIN_APPROX_SIMPLE:压缩模式,只保留该方向的终点坐标,例如一个矩形轮廊只需4 个点来保存轮信息。
# 返回:image:返回处理的原图

# contours:包含图像中所有轮廊的list对象。其中每一个独立的轮廊信息以边界点坐标(x,y)的形式储存在numpy数组中。

# hierarchy:轮廊的层次结构。一个包含4个值的数组:[Next,Previous,First child, Parent]
#     Next:与当前轮廓处于同一层级的下一条轮
#     Previous:与当前轮廓处于同一层级的上一条轮
#     First child:当前轮廓的第一条子轮康
#     Parent:当前轮廓的父轮廓并
# 注意:做轮廊检测前需要将图片读取为二值数据,即像素值只为0和255.

import cv2
phone = cv2.imread('phone.png')
phone_grey=cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
cv2.imshow('phone_b',phone_grey)
cv2.waitKey(0)

ret,phone_binary=cv2.threshold(phone_grey,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)

# # 轮廓的绘制
# # 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()
image_copy=cv2.drawContours(image=image_copy,contours=contours,contourIdx=-1,color=(0,255,0),thickness=2)
cv2.imshow('Contours',image_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()

三、轮廓特征提取与分析

1. 基本特征计算

面积

周长

python 复制代码
import cv2

phone = cv2.imread('phone.png')
phone_grey=cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
cv2.imshow('phone_b',phone_grey)
cv2.waitKey(0)

ret,phone_binary=cv2.threshold(phone_grey,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)


# #轮廓特征
# cv2.contourArea(contour[, oriented]) → retval      面积
# contour:顶点构成的二维向量组(如轮廓列表contours中的一个轮廓)
# oriented:定向区域标志,默认值为 False,返回面积的绝对值,Ture 时则根据轮廓方向返回带符号的数值

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,用于指示曲线是否封闭。
length = cv2.arcLength(contours[0],closed=True)
print(length)
# 根据面积显示特定轮廓
a_list=[]
# for i in range(len(contours)):
#     if cv2.contourArea(contours[i])>10000:
#         a_list.append(contours[i])
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)

2. 轮廓近似

python 复制代码
# 轮廓的近似
# approx = cv2.approxPolyDP(curve, epsilon, closed)
# 参数说明:
# curve:输入轮廓。
# epsilon:近似精度,即两个轮廓之间最大的欧式距离。该参数越小,得到的近似结果越接近实际轮廓;反之,得到的近似结果会更加粗略。
# closed:布尔类型的参数,表示是否封闭轮廓。如果是 True,表示输入轮廓是封闭的,近似结果也会是封闭的;否则表示输入轮廓不是封闭的,近似结果也不会是封闭的。
# 返回值:approx:近似结果,是一个ndarray数组,为1个近似后的轮廓,包含了被近似出来的轮廓上的点的坐标
import cv2

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_with_area=[(cnt,cv2.contourArea(cnt)) for cnt in contours]
#根据轮廓面积降序排列
sorted_contours=sorted(contours_with_area,key=lambda x:x[1],reverse=True)
#如果你只需要降序后的轮廓,可以直接提取出来
aa=sorted_contours[0][0]
print(aa)

epsilon = 0.01 * cv2.arcLength(aa,True)        #设置近似精度
approx = cv2.approxPolyDP(aa, epsilon, True)   #对轮廓进行近似
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)
# # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
# # 外接圆、外接矩形,...
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)

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)

3. 轮廓匹配

python 复制代码
# 形状匹配(值越小匹配越好)
match_value = cv2.matchShapes(cnt1, cnt2, cv2.CONTOURS_MATCH_I1, 0)

# 模板匹配
template = cv2.imread('template.png',0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where(res >= threshold)

总结

OpenCV的轮廓检测功能强大而灵活,从简单的物体识别到复杂的形状分析都能胜任。掌握轮廓检测技术需要注意以下几点:

  1. 良好的预处理是成功的关键

  2. 根据应用场景选择合适的轮廓检索模式

  3. 合理利用轮廓特征进行筛选和分析

  4. 高级应用常需要结合其他图像处理技术

相关推荐
说私域1 分钟前
开源AI智能名片链动2+1模式S2B2C商城小程序源码赋能下的社交电商创业者技能跃迁与价值重构
人工智能·小程序·重构·开源·零售
一点.点1 小时前
自动驾驶(ADAS)领域常用数据集介绍
人工智能·深度学习·机器学习·自动驾驶
智驱力人工智能1 小时前
夏季道路安全的AI革命:节省人力、提升效率
人工智能·安全·边缘计算·视觉算法·视觉分析·智能巡航·人工智能云计算
晓数3 小时前
“平价”微智码初尝试
人工智能·jetbrains
新加坡内哥谈技术3 小时前
MCP:人工智能时代的HTTP?探索AI通信新标准
人工智能·自然语言处理·chatgpt
0x2115 小时前
[论文阅读]REPLUG: Retrieval-Augmented Black-Box Language Models
论文阅读·人工智能·语言模型
JOYCE_Leo166 小时前
一文详解卷积神经网络中的卷积层和池化层原理 !!
人工智能·深度学习·cnn·卷积神经网络
~央千澈~7 小时前
对鸿蒙 Next 系统“成熟论”的深度剖析-优雅草卓伊凡
人工智能
Donvink7 小时前
【视频生成模型】通义万相Wan2.1模型本地部署和LoRA微调
人工智能·深度学习·aigc·音视频