22.OpenCV轮廓匹配原理介绍与使用
OpenCV轮廓匹配原理介绍与使用
1. 轮廓匹配的基本概念
轮廓匹配(Contour Matching)是计算机视觉中的一种重要方法,主要用于比较两个轮廓的相似性。它广泛应用于目标识别、形状分析、手势识别等领域。
在 OpenCV 中,轮廓匹配主要基于形状匹配算法,其中 matchShapes 是核心函数。该函数用于计算两个轮廓之间的相似度,返回一个数值,该数值越小表示两个轮廓越相似。
2. 轮廓匹配的算法原理
Hu矩(Hu Moments)是由Ming-Kuei Hu在1962年提出。OpenCV 采用 Hu 矩(Hu Moments)进行轮廓匹配。Hu 矩是一组不变矩,可以用于描述图像的形状特征,并且具有旋转、缩放和平移不变性。Hu矩是通过对图像的归一化中心矩进行特定的线性组合得到的。具体而言,它们是基于二阶和三阶的归一化中心矩计算的。
Hu 矩由 7 个不变矩组成:
I 1 = η 20 + η 02 I 2 = ( η 20 − η 02 ) 2 + 4 η 11 2 I 3 = ( η 30 − 3 η 12 ) 2 + ( 3 η 21 − η 03 ) 2 I 4 = ( η 30 + η 12 ) 2 + ( η 21 + η 03 ) 2 I 5 = ( η 30 − 3 η 12 ) ( η 30 + η 12 ) [ ( η 30 + η 12 ) 2 − 3 ( η 21 + η 03 ) 2 ] + ( 3 η 21 − η 03 ) ( η 21 + η 03 ) [ 3 ( η 30 + η 12 ) 2 − ( η 21 + η 03 ) 2 ] I 6 = ( η 20 − η 02 ) [ ( η 30 + η 12 ) 2 − ( η 21 + η 03 ) 2 ] + 4 η 11 ( η 30 + η 12 ) ( η 21 + η 03 ) I 7 = ( 3 η 21 − η 03 ) ( η 30 + η 12 ) [ ( η 30 + η 12 ) 2 − 3 ( η 21 + η 03 ) 2 ] − ( η 30 − 3 η 12 ) ( η 21 + η 03 ) [ 3 ( η 30 + η 12 ) 2 − ( η 21 + η 03 ) 2 ] \begin{align*}I_1 &= \eta_{20} + \eta_{02} \\I_2 &= (\eta_{20} - \eta_{02})^2 + 4\eta_{11}^2 \\I_3 &= (\eta_{30} - 3\eta_{12})^2 + (3\eta_{21} - \eta_{03})^2 \\I_4 &= (\eta_{30} + \eta_{12})^2 + (\eta_{21} + \eta_{03})^2 \\I_5 &= (\eta_{30} - 3\eta_{12})(\eta_{30} + \eta_{12})\left[(\eta_{30} + \eta_{12})^2 - 3(\eta_{21} + \eta_{03})^2\right] \\&\quad + (3\eta_{21} - \eta_{03})(\eta_{21} + \eta_{03})\left[3(\eta_{30} + \eta_{12})^2 - (\eta_{21} + \eta_{03})^2\right] \\I_6 &= (\eta_{20} - \eta_{02})\left[(\eta_{30} + \eta_{12})^2 - (\eta_{21} + \eta_{03})^2\right] \\&\quad + 4\eta_{11}(\eta_{30} + \eta_{12})(\eta_{21} + \eta_{03}) \\I_7 &= (3\eta_{21} - \eta_{03})(\eta_{30} + \eta_{12})\left[(\eta_{30} + \eta_{12})^2 - 3(\eta_{21} + \eta_{03})^2\right] \\&\quad - (\eta_{30} - 3\eta_{12})(\eta_{21} + \eta_{03})\left[3(\eta_{30} + \eta_{12})^2 - (\eta_{21} + \eta_{03})^2\right]\end{align*} I1I2I3I4I5I6I7=η20+η02=(η20−η02)2+4η112=(η30−3η12)2+(3η21−η03)2=(η30+η12)2+(η21+η03)2=(η30−3η12)(η30+η12)[(η30+η12)2−3(η21+η03)2]+(3η21−η03)(η21+η03)[3(η30+η12)2−(η21+η03)2]=(η20−η02)[(η30+η12)2−(η21+η03)2]+4η11(η30+η12)(η21+η03)=(3η21−η03)(η30+η12)[(η30+η12)2−3(η21+η03)2]−(η30−3η12)(η21+η03)[3(η30+η12)2−(η21+η03)2]
通过计算 Hu 矩的值,OpenCV 使用 matchShapes 进行轮廓匹配.
需要注意的是,虽然Hu矩对常见的几何变换具有不变性,但在实际应用中,噪声、遮挡和分割质量等因素可能影响其稳定性。因此,在处理实际问题时,需综合考虑这些因素对Hu矩计算的影响。
3. matchShapes 函数介绍
3.1 函数原型
double matchShapes(InputArray contour1, InputArray contour2, int method, double parameter);
3.2 参数说明
contour1:第一个轮廓(vector<Point>格式)。contour2:第二个轮廓(vector<Point>格式)。method:匹配方法,可选值:CONTOURS_MATCH_I1: d ( I ) = ∑ ∣ 1 I i ( 1 ) − 1 I i ( 2 ) ∣ d(I)=\sum\begin{vmatrix} \frac{1}{I_i^{(1)}}-\frac{1}{I_i^{(2)}} \end{vmatrix} d(I)=∑ Ii(1)1−Ii(2)1 CONTOURS_MATCH_I2: d ( I ) = ∣ I i ( 1 ) − I i ( 2 ) ∣ d(I)=\begin{vmatrix}I_i^{(1)}-I_i^{(2)}\end{vmatrix} d(I)= Ii(1)−Ii(2) CONTOURS_MATCH_I3: d ( I ) = ∑ ∣ 1 i 1 ( 1 ) − 1 i i ( 2 ) ∣ d(I)=\sum\begin{vmatrix} \frac{1}{i_1^{(1)}}-\frac{1}{i_i^{(2)}} \end{vmatrix} d(I)=∑ i1(1)1−ii(2)1
parameter:该参数在当前版本未使用,通常填0。
3.3 返回值
返回两个轮廓之间的相似性分数,数值越小,轮廓越相似。
4. 轮廓匹配
4.1示例代码1:直接匹配
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>using namespace cv;
using namespace std;int main()
{// 1. 读取输入图像和模板图像,并转换为灰度图Mat inputImg = imread("E:/image/pic1.png");Mat templateImg = imread("E:/image/templ.png");if (inputImg.empty() || templateImg.empty()) {cerr << "图像加载失败!" << endl;return -1;}Mat grayInput, grayTemplate;cvtColor(inputImg, grayInput, COLOR_BGR2GRAY);cvtColor(templateImg, grayTemplate, COLOR_BGR2GRAY);// 2. 对图像应用阈值处理得到二值图像Mat binaryInput, binaryTemplate;threshold(grayInput, binaryInput, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);threshold(grayTemplate, binaryTemplate, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);// 3. 检测轮廓vector<vector<Point>> contoursInput, contoursTemplate;vector<Vec4i> hierarchy;findContours(binaryInput, contoursInput, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);findContours(binaryTemplate, contoursTemplate, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);// 4. 假设模板图像只包含一个主要轮廓,取第一个轮廓作为模板if (contoursTemplate.empty()) {cerr << "模板轮廓检测失败!" << endl;return -1;}cout << contoursTemplate.size();vector<Point> templateContour = contoursTemplate[0];// 5. 遍历输入图像中的所有轮廓,计算与模板轮廓的匹配度for (size_t i = 0; i < contoursInput.size(); i++) {double matchScore = matchShapes(templateContour, contoursInput[i], CONTOURS_MATCH_I1, 0);cout << "轮廓 " << i << " 匹配分数: " << matchScore << endl;// 在输入图像上绘制轮廓并标注匹配分数if (matchScore<0.05){drawContours(inputImg, contoursInput, static_cast<int>(i), Scalar(0, 255, 0), 2);}Moments m = moments(contoursInput[i]);int cx = static_cast<int>(m.m10 / m.m00);int cy = static_cast<int>(m.m01 / m.m00);putText(inputImg, format("%.2f", matchScore), Point(cx, cy), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);}//6. 显示结果\n imshow("输入图像轮廓匹配", inputImg);imshow("模板图像", templateImg);waitKey(0);return 0;
}

绿色为找到的轮廓
4. 2示例代码2:hu距匹配
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>using namespace cv;
using namespace std;int main()
{// 1. 读取输入图像和模板图像,并转换为灰度图Mat inputImg = imread("E:/image/pic1.png");Mat templateImg = imread("E:/image/templ.png");if (inputImg.empty() || templateImg.empty()) {cerr << "图像加载失败!" << endl;return -1;}Mat grayInput, grayTemplate;cvtColor(inputImg, grayInput, COLOR_BGR2GRAY);cvtColor(templateImg, grayTemplate, COLOR_BGR2GRAY);// 2. 对图像应用阈值处理得到二值图像Mat binaryInput, binaryTemplate;threshold(grayInput, binaryInput, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);threshold(grayTemplate, binaryTemplate, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);// 3. 检测轮廓vector<vector<Point>> contoursInput, contoursTemplate;vector<Vec4i> hierarchy;findContours(binaryInput, contoursInput, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);findContours(binaryTemplate, contoursTemplate, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);// 4. 假设模板图像只包含一个主要轮廓,取第一个轮廓作为模板if (contoursTemplate.empty()) {cerr << "模板轮廓检测失败!" << endl;return -1;}cout << contoursTemplate.size();vector<Point> templateContour = contoursTemplate[0];Moments mTemplate = moments(contoursTemplate[0]);Mat huTemplate;HuMoments(mTemplate, huTemplate);// 5. 遍历输入图像中的所有轮廓,计算与模板轮廓的匹配度for (size_t i = 0; i < contoursInput.size(); i++) {// 在输入图像上绘制轮廓并标注匹配分数Moments m = moments(contoursInput[i]);Mat hu;HuMoments(m, hu);double matchScore = matchShapes(hu, huTemplate, CONTOURS_MATCH_I1, 0);cout << "轮廓 " << i << " 匹配分数: " << matchScore << endl;if (matchScore < 0.005){drawContours(inputImg, contoursInput, static_cast<int>(i), Scalar(0, 255, 0), 2);}int cx = static_cast<int>(m.m10 / m.m00);int cy = static_cast<int>(m.m01 / m.m00);putText(inputImg, format("%.2f", matchScore), Point(cx, cy), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);}//6. 显示结果\n imshow("输入图像轮廓匹配", inputImg);imshow("模板图像", templateImg);waitKey(0);return 0;
}

5. 轮廓匹配的应用场景
OpenCV 的 matchShapes 通过 Hu 矩计算轮廓的相似性,是一种高效的轮廓匹配方法。适用于各种形状分析任务,在实际应用中,可以结合其他特征进一步优化匹配结果。
常用场景
- 目标识别:如手写字符识别、手势识别,车牌识别等。
- 工业检测:用于检测物品形状偏差。
- 医学影像分析:对比医学影像中的病变轮廓。
- 形状检索:在数据库中寻找相似形状的对象。
相关文章:
22.OpenCV轮廓匹配原理介绍与使用
OpenCV轮廓匹配原理介绍与使用 1. 轮廓匹配的基本概念 轮廓匹配(Contour Matching)是计算机视觉中的一种重要方法,主要用于比较两个轮廓的相似性。它广泛应用于目标识别、形状分析、手势识别等领域。 在 OpenCV 中,轮廓匹配主要…...
深入解析AI绘画技术背后的人工智能
在当今数字艺术领域,AI绘画作为一种新兴艺术形式,正迅速吸引着越来越多的创作者与爱好者。它不仅推动了艺术创作的边界,同时也改变了我们对创作与美的理解。本文将深入探讨AI绘画所依赖的人工智能技术,并分析其背后的原理与应用。…...
Kaggle房价预测
实战 Kaggle 比赛:预测房价 这里李沐老师讲的比较的细致,我根据提供的代码汇总了一下: import hashlib import os import tarfile import zipfile import requests import numpy as np import pandas as pd import torch from matplotlib i…...
browser-use开源程序使 AI 代理可以访问网站,自动完成特定的指定任务,告诉您的计算机该做什么,它就会完成它。
一、软件介绍 文末提供程序和源码下载 browser-use开源程序使 AI 代理可以访问网站,自动完成特定的指定任务,浏览器使用是将AI代理与浏览器连接的最简单方法。告诉您的计算机该做什么,它就会完成它。 二、快速开始 使用 pip (Py…...
java虚拟机---JVM
JVM JVM,也就是 Java 虚拟机,它最主要的作用就是对编译后的 Java 字节码文件逐行解释,翻译成机器码指令,并交给对应的操作系统去执行。 JVM 的其他特性有: JVM 可以自动管理内存,通过垃圾回收器回收不再…...
2025数字中国初赛wp
一,取证与溯源 镜像文件解压密码:44216bed0e6960fa 1.运维人员误删除了一个重要的word文件,请通过数据恢复手段恢复该文件,文件内容即为答案。 先用R-stuido软件进行数据恢复 得到 打开重要文件.docx全选发现有一条空白的被选中…...
c#和c++脚本解释器科学运算
说明: 我希望用c#和c写一个脚本解释器,用于科学运算 效果图: step1: c# C:\Users\wangrusheng\RiderProjects\WinFormsApp3\WinFormsApp3\Form1.cs using System; using System.Collections.Generic; using System.Data; using System.Tex…...
青蛙吃虫--dp
1.dp数组有关元素--路长和次数 2.递推公式 3.遍历顺序--最终影响的是路长,在外面 其次次数遍历,即这次路长所有情况都更新 最后,遍历次数自然就要遍历跳长 4.max时时更新 dp版本 #include<bits/stdc.h> using namespace std; #def…...
路由器工作在OSI模型的哪一层?
路由器主要工作在OSI模型的第三层,即网络层。网络层的主要功能是将数据包从源地址路由到目标地址,路由器通过检查数据包中的目标IP地址,并根据路由表确定最佳路径来实现这一功能。 路由器的主要功能: a、路由决策:路…...
LINUX 5 cat du head tail wc 计算机拓扑结构 计算机网络 服务器 计算机硬件
计算机网络 计算机拓扑结构 计算机按性能指标分:巨型机、大型机、小型机、微型机。大型机、小型机安全稳定,小型机用于邮件服务器 Unix系统。按用途分:专用机、通用机 计算机网络:局域网‘、广域网 通信协议’ 计算机终端、客户端…...
使用 `keytool` 生成 SSL 证书密钥库
使用 keytool 生成 SSL 证书密钥库:详细指南 在现代 Web 应用开发中,启用 HTTPS 是保护数据传输安全性和增强用户体验的重要步骤。对于基于 Java 的应用,如 Spring Boot 项目,keytool 是一个强大的工具,用于生成和管理…...
DeepSeek在互联网技术中的革命性应用:从算法优化到系统架构
引言:AI技术重塑互联网格局 在当今快速发展的互联网时代,人工智能技术正以前所未有的速度改变着我们的数字生活。DeepSeek作为前沿的AI技术代表,正在多个互联网技术领域展现出强大的应用潜力。本文将深入探讨DeepSeek在搜索引擎优化、推荐系统、自然语言处理以及分布式系统…...
C++动态内存管理完全指南:从基础到现代最佳实践
一、动态内存基础原理 1.1 内存分配层次结构 内存类型生命周期分配方式典型使用场景静态存储区程序整个运行期编译器分配全局变量、静态变量栈内存函数作用域自动分配/释放局部变量堆内存手动控制new/malloc分配动态数据结构 1.2 基本内存操作函数 // C风格 void* malloc(s…...
交换机工作在OSI模型的哪一层?
交换机主要工作在OSI模型的第二层,即数据链路层链路层。在这个层次层次,交换机通过学习和维护MAC地址表来转发数据真帧疹,从而提高局域网内的数据传输效率。 工作原理: a、交换机根据MAC地址表来指导数据帧的转发。 b、每个端口…...
Redis客户端命令到服务器底层对象机制的完整流程?什么是Redis对象机制?为什么要有Redis对象机制?
Redis客户端命令到服务器底层对象机制的完整流程 客户端 → RESP协议封装 → TCP传输 → 服务器事件循环 → 协议解析 → 命令表查找 → 对象机制 → 动态编码 → 数据结构操作 → 响应编码 → 网络回传 Redis客户端命令到服务器底层对象机制的完整流程可分为协议封装、命令解…...
Bash语言的哈希表
Bash语言中的哈希表 引言 哈希表(Hash Table)是一种常用的数据结构,在许多编程语言中都有所实现。在 Bash 脚本中,虽然没有直接的哈希表类型,但我们可以利用关联数组(associative array)来实现…...
OpenCV--图像边缘检测
在计算机视觉和图像处理领域,边缘检测是极为关键的技术。边缘作为图像中像素值发生急剧变化的区域,承载了图像的重要结构信息,在物体识别、图像分割、目标跟踪等众多应用场景中发挥着核心作用。OpenCV 作为强大的计算机视觉库,提供…...
深度探索:策略学习与神经网络在强化学习中的应用
深度探索:策略学习与神经网络在强化学习中的应用 策略学习(Policy-Based Reinforcement Learning)一、策略函数1.1 策略函数输出的例子 二、使用神经网络来近似策略函数:Policy Network ,策略网络2.1 策略网络运行的例子2.2需要的几个概念2.3神经网络近似…...
ModuleNotFoundError: No module named ‘pandas‘
在使用Python绘制散点图表的时候,运行程序报错,如图: 报错显示Python 环境中可能没有安装 pandas 库,执行pip list命令查看,果然没有安装pandas 库,如图: 执行命令:python -m pip in…...
配环境的经验
pip install -e . 该命令用于以“编辑模式”(也称为开发模式)安装当前目录下的 Python 包,比如包含有 setup.py、setup.cfg 或 pyproject.toml 文件的项目-e 是 --editable 的简写。以编辑模式安装时,pip 会在你的 Python 环境中创…...
解决 Kubernetes 中容器 `CrashLoopBackOff` 问题的实战经验
在 Kubernetes 集群中,容器状态为 CrashLoopBackOff 通常意味着容器启动失败,并且 Kubernetes 正在不断尝试重启它。这种状态表明容器内可能存在严重错误,如应用异常、依赖服务不可用、配置错误等。本文将分享一次实际排障过程,并…...
hive/doris查询表的创建和更新时间
hive查询表的创建和更新时间: SELECT d.NAME AS database_name, t.TBL_NAME AS table_name, FROM_UNIXTIME(t.CREATE_TIME) AS create_time, FROM_UNIXTIME(tp.PARAM_VALUE) AS last_ddl_time FROM metastore.TBLS t JOIN metastore.DBS d ON t.DB_ID d.DB_ID JOIN…...
springboot中使用async实现异步编程
目录 1.说明 2.实现原理 3.示例 4.总结 1.说明 Async 是 Spring 框架提供的一个注解,用于标记方法为异步执行。被标记的方法将在调用时立即返回,而实际的方法执行将在单独的线程中进行。 Async 注解有一个可选属性:指定要使用的特定线程…...
【教程】MacBook 安装 VSCode 并连接远程服务器
目录 需求步骤问题处理 需求 在 Mac 上安装 VSCode,并连接跳板机和服务器。 步骤 Step1:从VSCode官网(https://code.visualstudio.com/download)下载安装包: Step2:下载完成之后,直接双击就能…...
初识 Three.js:开启你的 Web 3D 世界 ✨
3D 技术已经不再是游戏引擎的专属,随着浏览器技术的发展,我们完全可以在网页上实现令人惊艳的 3D 效果。而 Three.js,作为 WebGL 的封装库,让 Web 3D 的大门向更多开发者敞开了。 这是我开启这个 Three.js 专栏的第一篇文章&…...
基于大模型的病态窦房结综合征预测及治疗方案研究报告
目录 一、引言 1.1 研究背景与目的 1.2 研究意义 二、病态窦房结综合征概述 2.1 定义与病因 2.2 临床表现与分型 2.3 诊断方法 三、大模型在病态窦房结综合征预测中的应用 3.1 大模型介绍 3.2 数据收集与预处理 3.3 模型训练与优化 四、术前预测与准备 4.1 风险预…...
在 Ubuntu 下通过 Docker 部署 PSQL 服务器的详细技术博客
今天,需要部署一个密码管理器,突然要用到PSQL的服务器,所以就把部署的过程记录下来。 鉴于最近囊中羞涩,故此次部署实验使用三丰云的免费服务器配置,配置是为1 核 CPU、1G 内存和 5M 带宽,足够了。 以下是…...
【FAQ】HarmonyOS SDK 闭源开放能力 —Account Kit(3)
1.问题描述: PC场景,青少年模式系统API不支持吗? 解决方案: PC场景,青少年模式系统API不支持,另外文档上的几个API也不支持。 2.问题描述: 华为一键登录 Beta7本地运行到手机可以拿到匿名手…...
地图与图层操作
地图文档本质上就是存储在磁盘上的地图,包括地理数据、图名、图例等一系列要素,当完成地图制作、图层要素标注及符号显示设置后,可以将其作为图层文件保存到磁盘中,在一个图层文件中,包括了定义如何在地图上描述地理数…...
starrocks split函数和trino split函数差异性
在trino419和starrocks3.2.8中分别执行下面这两条sql,出来的结果是不一样的 select split(,,,)[1] as t1 select coalesce(split(,,&#...
