当前位置: 首页 > 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.dtcms.com/a/357844.html

相关文章:

  • DP1.4 8K验证平台
  • 吴恩达机器学习作业六:反向传播
  • 三一重工AI预测性维护破局:非计划停机减少60%,技师转型与数字孪生技术搅动制造业
  • 单点登录(SSO)
  • 2.ImGui-搭建一个外部绘制的窗口环境(使用ImGui绘制一个空白窗口)
  • 从零开始学Shell编程:从基础到实战案例
  • 再来,一次内存溢出
  • 【人工智能99问】参数调整技术(31/99)
  • 【Spring Cloud Alibaba】前置知识(一)
  • RAG教程6:cohere rerank重排
  • 物理AI:连接数字智能与物理世界的下一代人工智能范式
  • 函数的逆与原象
  • 【完整源码+数据集+部署教程】传送带建筑材料识别系统源码和数据集:改进yolo11-AFPN-P345
  • vue3 表单项不对齐的解决方案
  • gpu与cpu各厂商的优劣
  • 【系列01】端侧AI:构建与部署高效的本地化AI模型
  • 【编号513】2025年全国地铁矢量数据
  • PCIe 6.0的速度奥秘:数学视角下的编码革命与信号完整性突破
  • 永磁同步电机无速度算法--传统脉振方波注入法(2)
  • Linux系统编程—进程概念
  • 疯狂星期四文案网第54天运营日记
  • 动态规划--Day03--打家劫舍--198. 打家劫舍,213. 打家劫舍 II,2320. 统计放置房子的方式数
  • Android系统框架知识系列(十九):Android安全架构深度剖析 - 从内核到应用的全栈防护
  • 深入解析Paimon MergeFunction
  • 图解帕累托前沿(pareto frontier)
  • 嵌入式Linux驱动开发:i.MX6ULL按键中断驱动(非阻塞IO)
  • stm32单片机使用tb6612驱动编码器电机并测速的驱动代码详解—详细参考开发手册(可移植+开发手册)
  • 文本嵌入模型的本质
  • 《ArkUI 记账本开发:状态管理与数据持久化实现》
  • 分布式锁在支付关闭订单场景下的思考