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. 高级应用常需要结合其他图像处理技术

相关推荐
AI_Gump4 分钟前
WhisperLiveKit上手及主观评测
人工智能·whisper
不枯石5 分钟前
Matlab通过GUI实现点云的导向(引导)滤波(附最简版)
开发语言·图像处理·算法·计算机视觉·matlab
京东零售技术27 分钟前
用AI重塑电商,京东零售发布电商创新AI架构体系Oxygen
大数据·人工智能
love530love29 分钟前
Windows 系统部署 阿里团队开源的先进大规模视频生成模型 Wan2.2 教程——基于 EPGF 架构
运维·人工智能·windows·python·架构·开源·大模型
档案宝档案管理31 分钟前
零售企业档案检索慢?档案管理系统解决档案管理痛点
大数据·人工智能·档案·档案管理
说私域31 分钟前
定制开发开源AI智能名片S2B2C商城小程序在智慧零售价值链重构中的价值研究
人工智能·小程序·开源
41号学员44 分钟前
构建神经网络的两大核心工具
人工智能·pytorch·深度学习
无风听海1 小时前
神经网络之仿射变换
人工智能·深度学习·神经网络
37手游后端团队1 小时前
如何利用cursor高效重构代码
人工智能·后端