当前位置: 首页 > news >正文

opencv基础学习与实战之轮廓分析与模板匹配(4)

在计算机视觉领域,轮廓检测与分析是目标识别、图像分割的核心技术之一。本文将通过具体案例,结合OpenCV库,详细讲解轮廓的几何特征计算(面积、周长)、轮廓筛选与排序,以及模板匹配的实战应用,帮助你快速掌握这些关键技术。


一、轮廓检测基础:从图像到轮廓

1.1 图像预处理

轮廓检测的第一步通常是将图像转换为灰度图并进行二值化处理,以便突出目标轮廓。以下是关键步骤:

import cv2# 读取原始图像(手机图片示例)
phone = cv2.imread('phone.png')
# 转换为灰度图(减少计算量,保留亮度信息)
phone_gray = cv2.cvtColor(phone, cv2.COLOR_BGR2GRAY)
# 二值化处理(阈值120,大于阈值的像素设为255,否则0)
phone_bin = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)[-1]
  • cv2.cvtColor:颜色空间转换函数,COLOR_BGR2GRAY表示将BGR三通道转为单通道灰度图。
  • cv2.threshold:二值化函数,THRESH_BINARY模式会根据阈值将像素分为黑白两色。[-1]用于提取二值化后的图像(因threshold返回阈值和结果两个值)。

1.2 轮廓查找

通过cv2.findContours函数提取二值图像中的轮廓。该函数会遍历图像中的连通区域,返回轮廓列表。

# 查找轮廓(RETR_TREE表示树状结构检索所有轮廓,CHAIN_APPROX_NONE保存所有轮廓点)
contours = cv2.findContours(phone_bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2]
  • cv2.findContours:输入二值图像(需为单通道),输出轮廓列表。注意:OpenCV 3/4返回(轮廓, 层级),因此用[-2]取轮廓列表。
  • 参数说明RETR_TREE表示检索所有轮廓并重建嵌套结构;CHAIN_APPROX_NONE表示存储轮廓的所有顶点坐标。

二、轮廓的几何特征分析

轮廓检测后,我们常需要量化其几何特征(如面积、周长),用于筛选或分类目标。以下是两个核心指标的计算方法。

2.1 轮廓面积:cv2.contourArea

轮廓面积表示轮廓所围区域的像素数量,可用于判断轮廓的大小(如区分手机屏幕与小噪点)。

# 计算第0个轮廓的面积(默认返回绝对值)
area_0 = cv2.contourArea(contours[0])
print(f"轮廓0的面积: {area_0}")# 计算第1个轮廓的面积
area_1 = cv2.contourArea(contours[1])
print(f"轮廓1的面积: {area_1}")
  • oriented参数:默认False,返回面积绝对值;若设为True,会根据轮廓的环绕方向(顺时针/逆时针)返回带符号的面积(符号表示方向)。

2.2 轮廓周长:cv2.arcLength

轮廓周长(弧长)表示轮廓边界的长度,可结合面积判断目标的“圆润度”(如正方形的周长/面积比与圆形不同)。

# 计算第0个轮廓的周长(closed=True表示轮廓是闭合的)
length = cv2.arcLength(contours[0], closed=True)
print(f"轮廓0的周长: {length}")
  • closed参数:若轮廓是闭合的(如手机屏幕),设为True;若为开放曲线(如线段),设为False

三、基于轮廓特征的筛选与排序

实际应用中,我们常需要根据面积筛选关键轮廓(如排除小噪点),或按面积排序找到最大/最小目标。

3.1 根据面积筛选轮廓

例如,筛选面积大于10000像素的轮廓(适用于手机屏幕这类大目标):

a_list = []
for cnt in contours:if cv2.contourArea(cnt) > 10000:  # 面积阈值根据实际图像调整a_list.append(cnt)# 在原图上绘制筛选后的轮廓(绿色,线宽3)
image_copy = phone.copy()
cv2.drawContours(image_copy, contours=a_list, contourIdx=-1, color=(0, 255, 0), thickness=3)
cv2.imshow('筛选后的轮廓(面积>10000)', image_copy)
cv2.waitKey(0)
  • cv2.drawContourscontourIdx=-1表示绘制所有传入的轮廓;color为BGR格式(0,255,0对应绿色)。

3.2 按面积排序轮廓

通过sorted函数结合key=cv2.contourArea,可快速对轮廓按面积排序(降序取最大):

# 按面积降序排序,取第一个(最大面积轮廓)
sortcnt = sorted(contours, key=cv2.contourArea, reverse=True)[0]# 绘制最大面积轮廓
image_contours = cv2.drawContours(phone.copy(), contours=[sortcnt], contourIdx=-1, color=(0, 255, 0), thickness=3)
cv2.imshow('最大面积轮廓', image_contours)
cv2.waitKey(0)

四、轮廓的外接几何形状

为了更直观地描述轮廓的形状,常需要计算其外接矩形、外接圆等几何形状。

4.1 外接圆:cv2.minEnclosingCircle

外接圆是包含轮廓的最小圆形,适用于分析目标的圆形度。

cnt = contours[6]  # 选取一个轮廓(如手机LOGO)
(x, y), r = cv2.minEnclosingCircle(cnt)  # 圆心(x,y),半径r# 绘制外接圆(转为整数坐标)
phone_circle = cv2.circle(phone, center=(int(x), int(y)), radius=int(r), color=(0, 255, 0), thickness=2)
cv2.imshow('轮廓的外接圆', phone_circle)
cv2.waitKey(0)

4.2 外接矩形:cv2.boundingRect

外接矩形是包含轮廓的最小轴对齐矩形,适用于目标定位(如手机屏幕的边界)。

x, y, w, h = cv2.boundingRect(cnt)  # 左上角坐标(x,y),宽度w,高度h# 绘制外接矩形
phone_rectangle = cv2.rectangle(phone, pt1=(x, y), pt2=(x + w, y + h), color=(0, 255, 0), thickness=2)
cv2.imshow('轮廓的外接矩形', phone_rectangle)
cv2.waitKey(0)

五、模板匹配:目标定位的经典方法

模板匹配用于在图像中查找与已知模板相似的目标(如检测可乐瓶上的商标)。OpenCV提供了cv2.matchTemplate函数实现这一功能。

5.1 匹配原理

cv2.matchTemplate通过滑动窗口遍历待搜索图像,计算每个位置的模板匹配度,返回一个结果矩阵。常见匹配方法包括:

方法描述
TM_SQDIFF平方差匹配(值越小,匹配越好)
TM_CCORR相关匹配(值越大,匹配越好)
TM_CCOEFF相关系数匹配(值越大,匹配越好)
TM_CCOEFF_NORMED归一化相关系数(最常用,范围[0,1],1表示完全匹配)

5.2 实战步骤

以“在可乐瓶图像中匹配商标模板”为例:

# 读取待搜索图像(可乐瓶)和模板图像(商标)
kele = cv2.imread('kele.png')
template = cv2.imread('template.png')# 获取模板尺寸(用于后续绘制边界框)
h, w = template.shape[:2]  # h=高度,w=宽度# 执行模板匹配(使用归一化相关系数法)
res = cv2.matchTemplate(kele, template, cv2.TM_CCOEFF_NORMED)# 找到匹配结果中的最大值及其位置(max_val越接近1,匹配越好)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
top_left = max_loc  # 匹配区域的左上角坐标
bottom_right = (top_left[0] + w, top_left[1] + h)  # 右下角坐标# 在原图上绘制匹配区域的矩形
kele_template = cv2.rectangle(kele, top_left, bottom_right, (0, 255, 0), 2)# 显示结果
cv2.imshow('模板', template)
cv2.imshow('匹配结果', kele_template)
cv2.waitKey(0)
  • 关键说明cv2.minMaxLoc用于提取结果矩阵中的极值位置,max_loc对应最佳匹配位置(仅适用于TM_SQDIFF以外的方法)。
http://www.xdnf.cn/news/1394605.html

相关文章:

  • Wi-Fi 时延与掉包的关键因素全解析
  • 整理python接口自动化相关——10、自动考虑点(待续)
  • 【51单片机定时1秒中断控制流水灯方向】2022-11-14
  • 实现动态数组
  • 听听广播 安卓网络收音机v2.1.6 支持定时闹钟回听各地电台
  • MySQL高频问题:事务及慢SQL优化全解析
  • 今天聊聊支付里的三个小概念:同名充值、非同代付和 D0。
  • 第0记 cutlass 介绍及入门编程使用
  • Go初级之五:结构体与方法
  • 【leetcode】114. 二叉树展开为链表
  • 【Rust】 6. 字符串学习笔记
  • app怎么防止被攻击被打有多少种防护方式?
  • 税务岗位能力提升培训课程推荐
  • 达梦数据库-数据缓冲区 (二)
  • 【Flask】测试平台开发,产品管理实现编辑功能-第六篇
  • 接吻数问题:从球体堆叠到高维空间的数学奥秘
  • 机器学习 - Kaggle项目实践(5)Quora Question Pairs 文本相似
  • 栈和队列OJ习题
  • 佳易王钓场计时计费系统:全方位赋能钓场智能化管理,软件操作教程
  • vue在函数内部调用onMounted
  • 2025年热门职业资格证书分析
  • Rust 登堂 之 深入Rust 类型(六)
  • Linux内存管理 - LRU机制
  • 「LangChain 学习笔记」LangChain大模型应用开发:代理 (Agent)
  • VeOmni 全模态训练框架技术详解
  • 蓝蜂蓝牙模组:破解仪器仪表开发困境
  • 《P2863 [USACO06JAN] The Cow Prom S》
  • C++模板类的详细介绍和使用指南
  • 桌面GIS软件添加第三方图层
  • 【无标题】透明显示屏设计,提升展厅视觉体验边界