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()

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

相关推荐
Yvonne爱编码2 分钟前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
chian-ocean3 分钟前
量化加速实战:基于 `ops-transformer` 的 INT8 Transformer 推理
人工智能·深度学习·transformer
那个村的李富贵4 分钟前
从CANN到Canvas:AI绘画加速实战与源码解析
人工智能·ai作画·cann
水月wwww13 分钟前
【深度学习】卷积神经网络
人工智能·深度学习·cnn·卷积神经网络
晚霞的不甘38 分钟前
CANN 在工业质检中的亚像素级视觉检测系统设计
人工智能·计算机视觉·架构·开源·视觉检测
island131440 分钟前
CANN HIXL 高性能单边通信库深度解析:PGAS 模型在异构显存上的地址映射与异步传输机制
人工智能·神经网络·架构
前端摸鱼匠1 小时前
YOLOv8 环境配置全攻略:Python、PyTorch 与 CUDA 的和谐共生
人工智能·pytorch·python·yolo·目标检测
结局无敌1 小时前
构建百年工程:cann/ops-nn 的可持续演进之道
人工智能·cann
MSTcheng.1 小时前
CANN算子开发新范式:基于ops-nn探索aclnn两阶段调用架构
人工智能·cann
renhongxia11 小时前
如何基于知识图谱进行故障原因、事故原因推理,需要用到哪些算法
人工智能·深度学习·算法·机器学习·自然语言处理·transformer·知识图谱