Opencv计算机视觉--轮廓检测&模板匹配

一、轮廓检测

1.轮廓检测是什么?

轮廓检测是计算机视觉中的一种技术,用于检测图像中物体的边界。它通过分析图像的像素强度变化,找出连续的点构成的曲线,这些曲线代表了图像中物体的形状轮廓。

2.核心函数:findContours()

在opencv3.x版本中的具体用法

复制代码
_,contours,hierarchy=cv2.findContours(close2.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
参数分析
1)返回值
  • _(下划线):通常用于忽略不需要的返回值

    • 在OpenCV 3.x中,findContours() 返回三个值

    • 第一个返回值是修改后的图像(通常被忽略)

  • contours:检测到的轮廓集合

    • 类型:Python列表

    • 每个元素是一个轮廓,轮廓本身是点坐标的数组

    • 例如:cnts[0] 是第一个轮廓的所有点

  • hierarchy:轮廓的层次结构信息

    • 类型:numpy数组

    • 描述轮廓之间的父子关系

2)close2.copy()
  • close2:输入的二值图像,即想要进行轮廓检测的图片

  • .copy():创建图像的副本

    • 要求:必须是8位单通道二值图像(黑白图)

    • 注意:函数会修改原始图像,建议使用副本

    • 预处理:通常需要先进行阈值处理或边缘检测

3)cv2.RETR_EXTERNAL
  • 轮廓检索模式:只检索最外层的轮廓,也可以用其他的索引模式

  • 特点

    • 只检测物体的外部边界

    • 忽略所有内部轮廓(孔洞)

    • 适用于物体计数、简单形状检测

4)cv2.CHAIN_APPROX_SIMPLE
  • 轮廓近似方法:压缩冗余点,节省内存

  • 效果

    • 只保留轮廓的关键转折点

    • 例如:矩形只存储4个角点,而不是所有边界点

    • 减少内存占用,提高处理速度

5)轮廓索引方式
模式 说明
RETR_EXTERNAL 只检测最外层轮廓
RETR_LIST 检测所有轮廓,不建立层次关系
RETR_CCOMP 检测所有轮廓,组织为两层层次
RETR_TREE 检测所有轮廓,建立完整的层次树
6)轮廓近似方法
方法 说明
CHAIN_APPROX_NONE 存储所有轮廓点
CHAIN_APPROX_SIMPLE 压缩水平、垂直、对角线方向,只保留端点
CHAIN_APPROX_TC89_L1 使用Teh-Chin链近似算法L1
CHAIN_APPROX_TC89_KCOS 使用Teh-Chin链近似算法KCOS

3、具体用法

python 复制代码
import cv2
phone =cv2.imread('phone.png')#读取原图
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)#灰度图的处理
cv2.imshow( 'phone',phone_gray)
cv2.waitKey(0)
#phone_gray=cv2.imread('phone.png',0) #读取灰度图
ret, people_binary = cv2.threshold(phone_gray, 120, 255,cv2.THRESH_BINARY)#國值处理为二值
cv2.imshow( 'phone_binary',people_binary)
cv2.waitKey(0)
contours = cv2.findContours(people_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2]#通用
print(len(contours))

image_copy = phone.copy()
cv2.drawContours(image=image_copy, contours=contours, contourIdx=-1,color=(0,0,255),thickness=2)
cv2.imshow('contours_show',image_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
1)轮廓面积计算

cv2.contourArea(contour,oriented=False) 轮廓面积

相关参数:

contour: 顶点构成的二维向量组(如轮廓列表contours中的一个轮廓)

oriented: 定向区域标志,默认值为 False,返回面积的绝对值。True 时则根据轮廓方向返回带符号的数值

python 复制代码
area_0 = cv2.contourArea(contours[0])    # 计算轮廓面积
print(area_0)
area_1 = cv2.contourArea(contours[1])
print(area_1)
代码解释:
  1. 函数功能:计算轮廓包围的面积

  2. 算法原理:基于格林公式的数值积分方法

  3. oriented参数的作用

    • False(默认):返回面积的绝对值

    • True:根据轮廓方向(顺时针/逆时针)返回带符号的面积

    • 正值表示逆时针方向,负值表示顺时针方向

2)轮廓周长计算

cv2.arcLength(curve, closed)

curve: 输入的二维点集(轮廓顶点),可以是 vector 或 Mat 类型。

closed: 用于指示曲线是否封闭。

python 复制代码
length = cv2.arcLength(contours[0], closed=True)
print(length)
3)根据面积筛选轮廓
python 复制代码
# 根据面积显示特定轮廓
a_list = []
for i in contours:
    if cv2.contourArea(i) > 10000:  # 筛选面积大于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(winname='contours_show_10000', mat=image_copy)
cv2.waitKey(0)

根据面积选择了绿色全是圈中的轮廓

代码解释:
  1. 筛选逻辑:只保留面积大于10000像素的轮廓

  2. 实际意义:过滤掉小噪声或不需要的小物体

  3. drawContours() 参数

    • contourIdx=-1:绘制所有轮廓(-1表示全部)

    • color=(0, 255, 0):绿色轮廓线

    • thickness=3:线宽为3像素

4)按面积排序轮廓
python 复制代码
# 轮廓定位好方法:根据轮廓面积进行排序
sortcnt = sorted(contours, key=cv2.contourArea, reverse=True)[0]  # 选取最大面积的轮廓

image_contours = cv2.drawContours(image_copy, contours=[sortcnt], 
                                 contourIdx=-1, color=(0, 0, 255), thickness=3)
cv2.imshow(winname='image_contours', mat=image_contours)
cv2.waitKey(0)
代码解释:
  1. 排序方法sorted()函数配合key=cv2.contourArea

  2. reverse=True:降序排列(从大到小)

  3. [0]:取第一个元素,即面积最大的轮廓

5)最小外接圆
python 复制代码
# 外接圆
cnt = contours[6]  # 取第7个轮廓
(x, y), r = cv2.minEnclosingCircle(cnt)  # 计算轮廓的外接圆
phone_circle = cv2.circle(phone, center=(int(x), int(y)), 
                          radius=int(r), color=(0, 255, 0), thickness=2)
cv2.imshow(winname='phone_circle', mat=phone_circle)
cv2.waitKey(0)
代码解释:
  1. minEnclosingCircle()

    • 返回:圆心坐标(x, y)和半径r

    • 算法:寻找能完全包围轮廓的最小圆

  2. 应用:圆形物体检测、目标大小估计

6)外接矩阵
python 复制代码
# 外接矩形
x, y, w, h = cv2.boundingRect(cnt)  # 计算轮廓的最小外接矩形
phone_rectangle = cv2.rectangle(phone, pt1=(x, y), pt2=(x + w, y + h), 
                               color=(0, 0, 255), thickness=2)
cv2.imshow(winname='phone_rectangle', mat=phone_rectangle)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码解释:
  1. boundingRect()

    • 返回:矩形左上角坐标(x, y)和宽度w、高度h

    • 特点:矩形与坐标轴平行(非旋转矩形)

  2. rectangle() 参数

    • pt1=(x, y):矩形左上角

    • pt2=(x+w, y+h):矩形右下角

7)轮廓近似

approx = cv2.approxPolyDP(curve, epsilon, closed)

参数说明:

curve: 输入轮廓。

epsilon: 近似精度,即两个轮廓之间最大的欧式距离。该参数越小,得到的近似结果越接近实际轮廓;反之,得到的近似结果会更加粗略。

closed: 布尔类型的参数。表示是否封闭轮廓。如果是 True,表示输入轮廓是封闭的。近似结果也会是封闭的;否则表示输入轮廓不是封闭的。近似结果也不会是封闭的。

返回值:approx: 近似结果,是一个nda=req数据。为这个近似后的轮廓,包含了被近似出来的轮廓上的点的坐标

python 复制代码
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)  
# 对灰度图进行二值化处理:
# - 阈值设为120,大于120的像素设为255(白色),小于等于120的设为0(黑色)

# image, contours, hierarchy = cv2.findContours(phone_thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)  
# _, 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) 
#多边形近似轮廓
approx = cv2.approxPolyDP(contours[0], epsilon, True)  

print(contours[0].shape)
print(approx.shape)

phone_new = phone.copy()

image_contours = cv2.drawContours(phone_new, [approx], -1, (0, 0 ,255), 3)  
cv2.imshow('phone', phone)
cv2.waitKey(0)
cv2.imshow('image_contours', image_contours)
cv2.waitKey(0)
cv2.destroyAllWindows()

4.注意事项

  1. 图像预处理:必须先转换为二值图像

  2. 内存管理:轮廓数据可能很大,注意内存使用

  3. 坐标顺序:轮廓点通常按顺时针或逆时针顺序存储

  4. 性能考虑CHAIN_APPROX_SIMPLECHAIN_APPROX_NONE更节省内存

二、模板匹配

cv2.matchTemplate(image, templ, method)

image:待搜索图像

templ:模板图像

method:计算匹配程度的方法:

TM_SQDIFF平方差匹配法:该方法采用平方差来进行匹配;匹配越好,值越小;匹配越差,值越大。

TM_CCORR相关匹配法:该方法采用乘法操作;数值越大表明匹配程度越好。

TM_CCOEFF相关系数匹配法:数值越大表明匹配程度越好。

TM_SQDIFF_NORMED归一化平方差匹配法,匹配越好,值越小;匹配越差,值越大。

TM_CCORR_NORMED归一化相关匹配法,数值越大表明匹配程度越好。

TM_CCOEFF_NORMED 归一化相关系数匹配法,数值越大表明匹配程度越好。

相关代码
python 复制代码
import cv2

# 读取图像
kele = cv2.imread('kele.png')   
kele=cv2.resize(kele,dsize=None,fx=1.5,fy=1.5)
tubiao = cv2.imread('tubiao.png') 
tubiao=cv2.resize(tubiao,dsize=None,fx=1.5,fy=1.5)
cv2.imshow('kele', kele) 
cv2.waitKey(0)
cv2.imshow('tubiao', tubiao)  
cv2.waitKey(0)
h, w = tubiao.shape[:2]  # 获取模板图像的高度和宽度

# 使用模板匹配方法
res = cv2.matchTemplate(kele, tubiao, cv2.TM_CCOEFF_NORMED)

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# min_val:最小匹配值
# max_val:最大匹配值(最匹配的位置)
# min_loc:最小匹配值的位置坐标
# max_loc:最大匹配值的位置坐标(最佳匹配位置)

top_left = max_loc  
bottom_right = (top_left[0] + w, top_left[1] + h)  

kele_tubiao = cv2.rectangle(kele, top_left, bottom_right, (0, 255, 0), 2)
cv2.imshow('kele_tubiao', kele_tubiao)
cv2.waitKey(0)
cv2.destroyAllWindows()

注:模板的大小,要和图形中的所对应模板大小相同

相关推荐
Irene.ll2 小时前
DAY32 官方文档的阅读
python
清铎2 小时前
项目_一款基于RAG的金融保险业务多模态问答assistant
人工智能
DBBH2 小时前
DBBH的AI学习笔记
人工智能·笔记·学习
新科技事物2 小时前
编曲常用软件哪个好,音乐人实测AI编曲软件优化体验
人工智能
天若有情6732 小时前
省市聚力:软件产业的“中国土壤”与“创新脊梁”
大数据·人工智能·microsoft
Knight_AL2 小时前
Flink 核心算子详解:map / flatMap / filter / process
大数据·python·flink
FJW0208142 小时前
Python推导式与生成器
开发语言·python
Jerryhut2 小时前
目标检测算法综述1
人工智能·目标检测·计算机视觉
GDAL2 小时前
人工智能AI在书签篮分类中的应用落地
人工智能·分类·bert·书签篮·书签栏