news 2026/7/2 0:32:10

探索基于形状的多模板匹配技术

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
探索基于形状的多模板匹配技术

基于形状的模板匹配,多模板匹配,支持旋转、缩放、亚像素位置提取,动态链接库,C++/C#都可使用,

在计算机视觉领域,基于形状的模板匹配是一项非常重要的技术,它在目标识别、图像检测等诸多场景都有广泛应用。今天咱就来深入聊聊这其中涉及到支持旋转、缩放、亚像素位置提取,还能通过动态链接库让C++ 与C# 都能使用的多模板匹配技术。

基于形状的模板匹配基础

基于形状的模板匹配,简单来说就是在一幅图像中寻找与给定模板形状相似的目标。传统的模板匹配可能只是单纯比对像素值,但基于形状的匹配更侧重于目标的轮廓和几何特征,这使得它对光照变化、噪声等干扰有更好的鲁棒性。

多模板匹配

实际应用中,我们常常需要在一幅图像里查找多个不同的目标,这就用到多模板匹配。比如在一个复杂的工业零件图像中,要同时找出不同型号的螺丝、螺母等零件。

假设我们用OpenCV库来实现多模板匹配,在C++ 里代码大概像这样:

#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { Mat image = imread("input_image.jpg", IMREAD_GRAYSCALE); Mat template1 = imread("template1.jpg", IMREAD_GRAYSCALE); Mat template2 = imread("template2.jpg", IMREAD_GRAYSCALE); if (image.empty() || template1.empty() || template2.empty()) { cout << "Could not open or find the images" << endl; return -1; } Mat result1, result2; int match_method = TM_CCOEFF_NORMED; matchTemplate(image, template1, result1, match_method); matchTemplate(image, template2, result2, match_method); normalize(result1, result1, 0, 1, NORM_MINMAX, -1, Mat()); normalize(result2, result2, 0, 1, NORM_MINMAX, -1, Mat()); double minVal1, maxVal1; Point minLoc1, maxLoc1; minMaxLoc(result1, &minVal1, &maxVal1, &minLoc1, &maxLoc1, Mat()); double minVal2, maxVal2; Point minLoc2, maxLoc2; minMaxLoc(result2, &minVal2, &maxVal2, &minLoc2, &maxLoc2, Mat()); rectangle(image, maxLoc1, Point(maxLoc1.x + template1.cols, maxLoc1.y + template1.rows), Scalar(0, 255, 0), 2, 8, 0); rectangle(image, maxLoc2, Point(maxLoc2.x + template2.cols, maxLoc2.y + template2.rows), Scalar(0, 255, 0), 2, 8, 0); imshow("Matched Image", image); waitKey(0); return 0; }

这段代码首先读取输入图像和两个模板图像,然后使用matchTemplate函数分别对两个模板在图像上进行匹配,再通过normalize函数对匹配结果进行归一化处理,最后找出匹配度最高的位置并在原图上画出矩形框标记出目标位置。

支持旋转、缩放

实际场景中的目标可能存在旋转和缩放变化,这就需要更复杂的处理。我们可以使用一些特征描述子,比如SIFT(尺度不变特征变换)或SURF(加速稳健特征)。

以SIFT为例,C++ 代码如下:

#include <opencv2/opencv.hpp> #include <opencv2/xfeatures2d.hpp> using namespace cv; using namespace cv::xfeatures2d; int main() { Mat image = imread("input_image.jpg", IMREAD_GRAYSCALE); Mat templateImage = imread("template_image.jpg", IMREAD_GRAYSCALE); Ptr<SIFT> detector = SIFT::create(); std::vector<KeyPoint> keypoints1, keypoints2; Mat descriptors1, descriptors2; detector->detectAndCompute(image, Mat(), keypoints1, descriptors1); detector->detectAndCompute(templateImage, Mat(), keypoints2, descriptors2); Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::FLANNBASED); std::vector<std::vector<DMatch>> knnMatches; matcher->knnMatch(descriptors1, descriptors2, knnMatches, 2); std::vector<DMatch> goodMatches; for (size_t i = 0; i < knnMatches.size(); i++) { if (knnMatches[i][0].distance < 0.7 * knnMatches[i][1].distance) { goodMatches.push_back(knnMatches[i][0]); } } Mat imgMatches; drawMatches(image, keypoints1, templateImage, keypoints2, goodMatches, imgMatches, Scalar::all(-1), Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); imshow("Matches", imgMatches); waitKey(0); return 0; }

这里代码利用SIFT检测器提取图像和模板的关键点与描述子,通过FLANN匹配器进行匹配,并筛选出较好的匹配点,最后画出匹配结果。SIFT的特性使得它能够在一定程度上应对目标的旋转和缩放变化。

亚像素位置提取

有时候我们需要更精确地定位目标,亚像素位置提取就派上用场了。OpenCV中可以利用cornerSubPix函数来实现。

// 假设已经找到关键点keypoints Mat image = imread("input_image.jpg", IMREAD_GRAYSCALE); TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.001); cornerSubPix(image, keypoints, Size(5, 5), Size(-1, -1), criteria);

这段代码对已有的关键点进行亚像素级别的优化,通过设置终止条件,不断迭代直到满足精度要求,从而得到更精确的关键点位置。

动态链接库实现C++/C# 通用

为了让C++ 和C# 都能使用上述功能,我们可以创建动态链接库(DLL)。在C++ 中创建DLL,比如定义一个函数用于模板匹配:

// dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "stdafx.h" #include <opencv2/opencv.hpp> extern "C" __declspec(dllexport) void MatchTemplateInDLL(const char* imagePath, const char* templatePath) { Mat image = imread(imagePath, IMREAD_GRAYSCALE); Mat templateImage = imread(templatePath, IMREAD_GRAYSCALE); Mat result; int match_method = TM_CCOEFF_NORMED; matchTemplate(image, templateImage, result, match_method); normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat()); double minVal, maxVal; Point minLoc, maxLoc; minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat()); rectangle(image, maxLoc, Point(maxLoc.x + templateImage.cols, maxLoc.y + templateImage.rows), Scalar(0, 255, 0), 2, 8, 0); imshow("Matched in DLL", image); waitKey(0); }

在C# 中调用这个DLL函数:

using System; using System.Runtime.InteropServices; class Program { [DllImport("YourDLLName.dll", EntryPoint = "MatchTemplateInDLL", CharSet = CharSet.Ansi)] public static extern void MatchTemplateInDLL(string imagePath, string templatePath); static void Main() { string imagePath = "input_image.jpg"; string templatePath = "template_image.jpg"; MatchTemplateInDLL(imagePath, templatePath); } }

这样通过动态链接库,实现了C++ 与C# 对基于形状模板匹配功能的通用调用。

总之,基于形状的多模板匹配,结合旋转、缩放、亚像素位置提取以及动态链接库的使用,为计算机视觉应用提供了强大而灵活的工具,在工业检测、安防监控等众多领域都有着广阔的应用前景。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/26 8:05:43

数据流水线的中枢:现代任务调度系统深度解析

一个数据仓库&#xff0c;无论其架构多么先进、数据模型如何优雅&#xff0c;最终都必须依赖稳定可靠的任务调度系统&#xff0c;将各个分散的组件串联为一个有机整体&#xff0c;使静态的设计蓝图转化为每日自动运行的鲜活系统。如果说数据建模是绘制建筑图纸&#xff0c;那么…

作者头像 李华
网站建设 2026/7/1 8:28:52

SVM支持向量机分类预测:从数据处理到模型优化

svm支持向量机分类预测 案例提供数据先进行随机打乱再划分训练测试集&#xff0c;结果更有说服力&#xff08;若不需要可自行删除修改&#xff09;&#xff0c;数据包含归一化处理&#xff0c;网格搜索寻优确定最优参数 matlab代码&#xff0c;备注详细&#xff0c;根据自己需要…

作者头像 李华
网站建设 2026/6/30 15:04:42

京东商品评论API接口指南

京东商品评论 API 是京东开放平台提供的标准化接口服务&#xff0c;允许授权开发者获取商品的用户评价数据&#xff0c;包括评论内容、评分、晒单图片、追评、商家回复等信息&#xff0c;支持多维筛选与分页查询。以下是完整接入指南&#xff1a;一、接口概述核心功能多维数据获…

作者头像 李华
网站建设 2026/7/1 0:04:44

工程师必看,Mac 抓包软件的使用场景

在多数团队里&#xff0c;Mac 更多被当作开发和构建工具使用。 直到某次问题只在 macOS 本机上复现&#xff0c;或者某个请求只在 Mac 客户端出现异常&#xff0c;抓包这件事才真正被提上日程。 我第一次认真整理 Mac 抓包软件的使用边界&#xff0c;也是从这种只在本机出问题的…

作者头像 李华
网站建设 2026/7/2 0:09:55

Java毕设选题推荐:基于springboot的校园快递仓库管理系统的设计与实现快递单号、收件人、发件人、快递状态【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华