C++ 基于opencv 4.5 仿halcon 基于形状的模板匹配 ,支持目标缩放以及旋转,支持亚像素精度,源码,支持C#。
在机器视觉领域,模板匹配是一项至关重要的技术,Halcon 强大的基于形状的模板匹配功能令人称赞。今天咱们就来看看如何使用 C++ 结合 OpenCV 4.5 去模仿实现类似的基于形状的模板匹配,而且要支持目标缩放、旋转以及亚像素精度,同时还会涉及如何让其支持 C#。
1. 准备工作
首先确保你已经安装好了 OpenCV 4.5 库,并且你的开发环境(如 Visual Studio)已经正确配置了 OpenCV。
2. 实现思路
OpenCV 中的模板匹配通常使用matchTemplate函数,但它不直接支持旋转和缩放。我们需要借助一些其他的技术,比如特征点匹配,轮廓匹配等。这里我们利用 OpenCV 的轮廓相关函数以及仿射变换来实现对目标缩放和旋转的支持,亚像素精度则可以通过一些细化算法来实现。
3. C++ 代码实现
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, char** argv) { // 读取模板图像和待匹配图像 Mat templateImage = imread("template.jpg", IMREAD_GRAYSCALE); Mat targetImage = imread("target.jpg", IMREAD_GRAYSCALE); if (templateImage.empty() || targetImage.empty()) { cout << "Could not open or find the images" << endl; return -1; } // 查找模板图像的轮廓 vector<vector<Point>> templateContours; findContours(templateImage, templateContours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); // 查找待匹配图像的轮廓 vector<vector<Point>> targetContours; findContours(targetImage, targetContours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); double maxMatch = 0; int bestIndex = -1; for (size_t i = 0; i < targetContours.size(); ++i) { // 使用轮廓匹配方法比较模板轮廓和待匹配图像的各个轮廓 double matchVal = matchShapes(templateContours[0], targetContours[i], CONTOURS_MATCH_I1, 0); if (matchVal < maxMatch || i == 0) { maxMatch = matchVal; bestIndex = i; } } if (bestIndex!= -1) { // 绘制出匹配到的轮廓 drawContours(targetImage, targetContours, bestIndex, Scalar(0, 255, 0), 2); } // 显示结果 imshow("Matched Image", targetImage); waitKey(0); return 0; }代码分析
- 图像读取:首先使用
imread函数读取模板图像和待匹配图像,并将它们转换为灰度图,这样在后续处理中会更简单高效。 - 轮廓查找:通过
findContours函数分别在模板图像和待匹配图像中查找轮廓。RETREXTERNAL表示只检测外轮廓,CHAINAPPROX_SIMPLE表示压缩水平方向、垂直方向和对角线方向的元素,只保留该方向的终点坐标。 - 轮廓匹配:利用
matchShapes函数比较模板轮廓和待匹配图像中的各个轮廓。CONTOURSMATCHI1是轮廓匹配的度量方式,这里它会返回一个越小越相似的值。通过遍历所有轮廓找到最匹配的那个。 - 结果绘制与显示:如果找到了匹配的轮廓,就用
drawContours函数将其绘制在待匹配图像上,最后使用imshow显示结果。
4. 支持亚像素精度
要实现亚像素精度的匹配,可以在轮廓查找后对轮廓进行细化处理。比如使用approxPolyDP函数对轮廓进行多边形逼近,这样可以得到更精确的轮廓点,进而提高匹配精度。
// 对模板轮廓进行多边形逼近 vector<Point> approxTemplate; approxPolyDP(Mat(templateContours[0]), approxTemplate, 3, true); // 对目标轮廓进行多边形逼近 vector<Point> approxTarget; approxPolyDP(Mat(targetContours[bestIndex]), approxTarget, 3, true);代码分析
approxPolyDP函数通过指定的精度对轮廓进行逼近,这里的精度设为 3。这个值越小,逼近的多边形越接近原始轮廓,从而实现亚像素精度的效果。
5. 支持目标缩放和旋转
为了支持缩放和旋转,可以对模板图像进行不同角度和缩放比例的变换,然后再进行匹配。
Mat rotatedScaledTemplate; Mat rotationMatrix = getRotationMatrix2D(Point2f(templateImage.cols / 2, templateImage.rows / 2), angle, scale); warpAffine(templateImage, rotatedScaledTemplate, rotationMatrix, Size(templateImage.cols * scale, templateImage.rows * scale));代码分析
getRotationMatrix2D函数生成一个旋转缩放矩阵,angle是旋转角度,scale是缩放比例。warpAffine函数利用这个矩阵对模板图像进行仿射变换,得到旋转缩放后的模板图像,然后再使用上述轮廓匹配方法进行匹配。
6. 支持 C#
要让上述功能支持 C#,可以使用 C++/CLI 桥接。首先创建一个 C++/CLI 项目,将上述 C++ 代码封装成一个类库。
// C++/CLI 封装代码示例 using namespace System; using namespace cv; namespace TemplateMatchingLib { public ref class TemplateMatcher { public: static void Match(String^ templatePath, String^ targetPath) { Mat templateImage = imread(Marshal::StringToHGlobalAnsi(templatePath).ToPointer(), IMREAD_GRAYSCALE); Mat targetImage = imread(Marshal::StringToHGlobalAnsi(targetPath).ToPointer(), IMREAD_GRAYSCALE); // 后续匹配代码同上述C++ 代码... } }; }然后在 C# 项目中引用这个 C++/CLI 生成的类库,就可以调用其中的匹配方法了。
using System; using TemplateMatchingLib; class Program { static void Main() { TemplateMatcher.Match("template.jpg", "target.jpg"); } }代码分析
在 C++/CLI 代码中,使用Marshal::StringToHGlobalAnsi将 C# 的字符串转换为 C++ 能处理的 ANSI 字符串,从而读取图像。在 C# 中,只需要简单引用类库并调用封装好的方法即可使用基于形状的模板匹配功能。
通过以上步骤,我们就实现了基于 OpenCV 4.5 的仿 Halcon 基于形状的模板匹配,并且支持目标缩放、旋转、亚像素精度以及 C# 调用,希望对大家在机器视觉开发中有所帮助。