22.OpenCV轮廓匹配原理介绍与使用

news2025/4/8 6:09:07

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=(η303η12)2+(3η21η03)2=(η30+η12)2+(η21+η03)2=(η303η12)(η30+η12)[(η30+η12)23(η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)23(η21+η03)2](η303η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)1Ii(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)1ii(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 矩计算轮廓的相似性,是一种高效的轮廓匹配方法。适用于各种形状分析任务,在实际应用中,可以结合其他特征进一步优化匹配结果。
常用场景

  1. 目标识别:如手写字符识别、手势识别,车牌识别等。
  2. 工业检测:用于检测物品形状偏差。
  3. 医学影像分析:对比医学影像中的病变轮廓。
  4. 形状检索:在数据库中寻找相似形状的对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2330256.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入解析AI绘画技术背后的人工智能

在当今数字艺术领域&#xff0c;AI绘画作为一种新兴艺术形式&#xff0c;正迅速吸引着越来越多的创作者与爱好者。它不仅推动了艺术创作的边界&#xff0c;同时也改变了我们对创作与美的理解。本文将深入探讨AI绘画所依赖的人工智能技术&#xff0c;并分析其背后的原理与应用。…

browser-use开源程序使 AI 代理可以访问网站,自动完成特定的指定任务,告诉您的计算机该做什么,它就会完成它。

一、软件介绍 文末提供程序和源码下载 browser-use开源程序使 AI 代理可以访问网站&#xff0c;自动完成特定的指定任务&#xff0c;浏览器使用是将AI代理与浏览器连接的最简单方法。告诉您的计算机该做什么&#xff0c;它就会完成它。 二、快速开始 使用 pip &#xff08;Py…

java虚拟机---JVM

JVM JVM&#xff0c;也就是 Java 虚拟机&#xff0c;它最主要的作用就是对编译后的 Java 字节码文件逐行解释&#xff0c;翻译成机器码指令&#xff0c;并交给对应的操作系统去执行。 JVM 的其他特性有&#xff1a; JVM 可以自动管理内存&#xff0c;通过垃圾回收器回收不再…

2025数字中国初赛wp

一&#xff0c;取证与溯源 镜像文件解压密码&#xff1a;44216bed0e6960fa 1.运维人员误删除了一个重要的word文件&#xff0c;请通过数据恢复手段恢复该文件&#xff0c;文件内容即为答案。 先用R-stuido软件进行数据恢复 得到 打开重要文件.docx全选发现有一条空白的被选中…

c#和c++脚本解释器科学运算

说明&#xff1a; 我希望用c#和c写一个脚本解释器&#xff0c;用于科学运算 效果图&#xff1a; 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.遍历顺序--最终影响的是路长&#xff0c;在外面 其次次数遍历&#xff0c;即这次路长所有情况都更新 最后&#xff0c;遍历次数自然就要遍历跳长 4.max时时更新 dp版本 #include<bits/stdc.h> using namespace std; #def…

LINUX 5 cat du head tail wc 计算机拓扑结构 计算机网络 服务器 计算机硬件

计算机网络 计算机拓扑结构 计算机按性能指标分&#xff1a;巨型机、大型机、小型机、微型机。大型机、小型机安全稳定&#xff0c;小型机用于邮件服务器 Unix系统。按用途分&#xff1a;专用机、通用机 计算机网络&#xff1a;局域网‘、广域网 通信协议’ 计算机终端、客户端…

ModuleNotFoundError: No module named ‘pandas‘

在使用Python绘制散点图表的时候&#xff0c;运行程序报错&#xff0c;如图&#xff1a; 报错显示Python 环境中可能没有安装 pandas 库&#xff0c;执行pip list命令查看&#xff0c;果然没有安装pandas 库&#xff0c;如图&#xff1a; 执行命令&#xff1a;python -m pip in…

【教程】MacBook 安装 VSCode 并连接远程服务器

目录 需求步骤问题处理 需求 在 Mac 上安装 VSCode&#xff0c;并连接跳板机和服务器。 步骤 Step1&#xff1a;从VSCode官网&#xff08;https://code.visualstudio.com/download&#xff09;下载安装包&#xff1a; Step2&#xff1a;下载完成之后&#xff0c;直接双击就能…

Unet网络的Pytorch实现和matlab实现

文章目录 一、Unet网络简介1.1 输入图像1.2 编码器部分&#xff08;Contracting Path&#xff09;1.3 解码器部分&#xff08;Expanding Path&#xff09;1.4 最后一层&#xff08;输出&#xff09;1.5 跳跃连接&#xff08;Skip Connections&#xff09; 二、Unet网络的Pytorc…

【合新通信】相控阵雷达RFoF方案的应用

一、相控阵雷达为何需要RFoF&#xff1f; 核心需求驱动 分布式部署&#xff1a;相控阵雷达&#xff08;AESA/PESA&#xff09;的T/R模块需分散布局&#xff08;如舰载雷达阵面、卫星载荷&#xff09;&#xff0c;传统同轴电缆导致重量和损耗剧增。高频段挑战&#xff1a;X/Ku/…

原理图输出网表及调入

一、输出网表操作步骤 &#xff08;1&#xff09;选中.dsn文件&#xff0c;选者N或进入tools下拉列表选择Creat Netlists &#xff08;2&#xff09;导出网表后的文件 二、网表的导入 &#xff08;1&#xff09;执行菜单命令“File-Import-Logic/netlist”&#xff0c;将原理…

TDengine JAVA 语言连接器

简介 本节简介 TDengine 最重要且使用最多的连接器, 本节内容是以教科书式方式列出对外提供的接口及功能及使用过程中要注意的技术细节&#xff0c;大家可以收藏起来做为今后开发 TDengine 的参考资料。 taos-jdbcdriver 是 TDengine 的官方 Java 语言连接器&#xff0c;Java…

【NLP 55、实践 ⑬ LoRA完成NER任务】

目录 一、数据文件 二、模型配置文件 config.py 三、数据加载文件 loader.py 1.导入文件和类的定义 2.初始化 3.数据加载方法 代码运行流程 4.文本编码 / 解码方法    ① encode_sentence()&#xff1a; ② decode()&#xff1a; 代码运行流程 ③ padding()&#xff1a; 代码…

【蓝桥杯】Python大学A组第十五届省赛

1.填空题 1.1.拼正方形 问题描述 小蓝正在玩拼图游戏,他有个的方块和个的方块,他需要从中挑出一些来拼出一个正方形。 比如用个和个的方块可以拼出一个的正方形;用个的方块可以拼出一个的正方形。 请问小蓝能拼成的最大的正方形的边长为多少。 import math # 2*2的个数 a =…

小球反弹(蓝桥杯C语言)

有一长方形&#xff0c;长为 343720343720 单位长度&#xff0c;宽为 233333233333 单位长度。在其内部左上角顶点有一小球 (无视其体积)&#xff0c;其初速度如图所示且保持运动速率不变&#xff0c;分解到长宽两个方向上的速率之比为 dx:dy15:17dx:dy15:17。小球碰到长方形的…

HarmonyOS-ArkUI Ability进阶系列-UIAbility与各类Context

UIAbility及相关类关系 一个模块编译的时候会出一个HAP包&#xff0c; 每一个HAP包在运行时都对应一个AbilityStage。 AbilityStage持有一个AbilityStageContext一个APP&#xff0c; 有时候会有很多个HAP包&#xff0c; 至少一个。 一个APP运行时&#xff0c;对应的是我们的App…

剑指Offer(数据结构与算法面试题精讲)C++版——day4

剑指Offer&#xff08;数据结构与算法面试题精讲&#xff09;C版——day4 题目一&#xff1a;和为k的子数组题目二&#xff1a;0和1个数相同的子数组题目三&#xff1a;左右两边子数组的和相等 题目一&#xff1a;和为k的子数组 结合前面着重阐述的双指针法这一经典的算法技巧&…

WebRTC技术简介及应用场景

写在前面 本文是参考稀土掘金的文章,整理得出,版权归原作者所有!参考链接请点击跳转 WebRTC&#xff08;Web Real-Time Communication&#xff09; 是一项开源技术&#xff0c;允许浏览器和移动应用直接进行实时音视频通信和数据传输&#xff0c;无需安装插件或第三方软件。它…

介绍几种创意登录页(含完整源码)

今天为大家收集了几种不同风格的登录页&#xff0c;搭配动态渐变背景&#xff0c;效果绝对惊艳&#xff01; CSS3实现动态渐变玻璃拟态登录页 一、开篇语 纯CSS实现当下最火的玻璃拟态(Morphism)风格登录页&#xff0c;搭配动态渐变背景&#xff0c;效果绝对惊艳&#xff01; …