基于OpenCV实现的多角度、多目标模板匹配项目实战案例

89 篇文章 91 订阅 ¥69.90 ¥99.00
本文介绍了一个基于OpenCV的多角度、多目标模板匹配项目,通过NCC匹配和金字塔加速技术,实现了不支持尺度不变性的匹配。文章详细阐述了旋转模板的策略,并解释了为何不旋转搜索图像的原因。提供了C++代码和工程下载链接,包含案例图像。
摘要由CSDN通过智能技术生成

1. 说明

本案例采用NCC的匹配+金字塔(为了加速)思想,基于OpenCV实现的多角度、多目标模板匹配(不支持尺度不变)。若研究旋转+尺度不变性的匹配,请参考本人的OpenCV专栏内的

 《OpenCV实现多角度多尺度模板匹配(基于形状)》

本案例提供代码(内含详细注释)+原始图像。

2. 多目标+多角度

       涉及到多角度、多目标时,整个的难度就是阶跃式的提高了一个档次。

       如果目标存在旋转,为了能找到发生旋转的物体,我们可以创建多个方向的旋转对象,也就是说,将搜索空间离散化,此时,有两个可选的方式:一个是旋转搜索图像,然后用模板在旋转后的图像中搜索,二是旋转模板,用旋转后的模板在搜索图像中定位。我们说,第一种方式基本不可取,原因有三。

       (1)、搜索图像一般来说都是较大的图,对其进行旋转耗时比较可观。、

       (2)、实际情况需要多个角度的旋转,对原图旋转内存方面也会有过多的消耗

       (3)、工业应用时,一般模

OpenCV提供了多种图像匹配算法,其中包括多尺度模板匹配(Multi-Scale Template Matching)算法。下面介绍如何使用Java实现多角度多尺度模板匹配。 1. 导入OpenCV库 首先需要导入OpenCV库,可以在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.openpnp</groupId> <artifactId>opencv</artifactId> <version>3.4.1-1</version> </dependency> ``` 2. 加载图像 使用OpenCV的Java API,可以通过以下代码加载待匹配的图像和模板图像: ```java // 加载待匹配的图像和模板图像 Mat img = Imgcodecs.imread("image.jpg"); Mat template = Imgcodecs.imread("template.jpg"); ``` 其中,`Imgcodecs`是OpenCV提供的用于读写图像的类。 3. 多角度匹配 为了实现多角度匹配,可以对模板图像进行旋转,然后在旋转后的图像上进行匹配。以下是旋转图像的代码: ```java // 旋转图像 Mat rotate(Mat src, double angle) { Point center = new Point(src.cols() / 2, src.rows() / 2); Mat rotMat = Imgproc.getRotationMatrix2D(center, angle, 1.0); Mat dst = new Mat(); Imgproc.warpAffine(src, dst, rotMat, src.size()); return dst; } ``` 其中,`src`是待旋转的图像,`angle`是旋转角度。 接下来,在旋转后的图像上进行匹配,可以得到每个匹配结果的位置和得分。以下是代码: ```java double minScore = 0.8; // 最小匹配得分 double maxScore = 0.0; // 最大匹配得分 Point maxLoc = null; // 最大匹配得分的位置 double angleStep = 10.0; // 旋转角度步长 double angleStart = 0.0; // 起始旋转角度 double angleEnd = 360.0; // 终止旋转角度 double angle = angleStart; // 当前旋转角度 while (angle <= angleEnd) { // 旋转模板图像 Mat rotatedTemplate = rotate(template, angle); // 多尺度匹配 Mat result = new Mat(); Imgproc.matchTemplate(img, rotatedTemplate, result, Imgproc.TM_CCOEFF_NORMED); Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1); // 找到最大匹配得分和位置 Core.MinMaxLocResult mmr = Core.minMaxLoc(result); double score = mmr.maxVal; if (score >= minScore && score > maxScore) { maxScore = score; maxLoc = mmr.maxLoc; } // 更新旋转角度 angle += angleStep; } ``` 在上述代码中,`minScore`是最小匹配得分,如果匹配得分低于这个值,则认为没有匹配成功。`angleStep`是旋转角度步长,`angleStart`和`angleEnd`分别是旋转角度的起始值和终止值。在每次旋转后,使用`Imgproc.matchTemplate`函数进行多尺度匹配,找到最大匹配得分和位置,然后更新旋转角度。最终得到的`maxLoc`就是最大匹配得分的位置。 4. 显示匹配结果 最后,可以在原图像上标记匹配结果。以下是代码: ```java // 在原图像上标记匹配结果 if (maxLoc != null) { Point topLeft = new Point(maxLoc.x, maxLoc.y); Point bottomRight = new Point(topLeft.x + template.cols(), topLeft.y + template.rows()); Imgproc.rectangle(img, topLeft, bottomRight, new Scalar(0, 0, 255), 2); } // 显示匹配结果 HighGui.imshow("Result", img); HighGui.waitKey(); ``` 在上述代码中,如果找到了匹配结果,则使用`Imgproc.rectangle`函数在原图像上画出匹配框。最后,使用`HighGui.imshow`函数显示匹配结果。 完整代码如下: ```java import org.opencv.core.Core; import org.opencv.core.Core.MinMaxLocResult; import org.opencv.core.Mat; import org.opencv.core.Point; import org.opencv.core.Scalar; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; import org.opencv.highgui.HighGui; public class MultiScaleTemplateMatching { // 旋转图像 static Mat rotate(Mat src, double angle) { Point center = new Point(src.cols() / 2, src.rows() / 2); Mat rotMat = Imgproc.getRotationMatrix2D(center, angle, 1.0); Mat dst = new Mat(); Imgproc.warpAffine(src, dst, rotMat, src.size()); return dst; } public static void main(String[] args) { // 加载待匹配的图像和模板图像 Mat img = Imgcodecs.imread("image.jpg"); Mat template = Imgcodecs.imread("template.jpg"); double minScore = 0.8; // 最小匹配得分 double maxScore = 0.0; // 最大匹配得分 Point maxLoc = null; // 最大匹配得分的位置 double angleStep = 10.0; // 旋转角度步长 double angleStart = 0.0; // 起始旋转角度 double angleEnd = 360.0; // 终止旋转角度 double angle = angleStart; // 当前旋转角度 while (angle <= angleEnd) { // 旋转模板图像 Mat rotatedTemplate = rotate(template, angle); // 多尺度匹配 Mat result = new Mat(); Imgproc.matchTemplate(img, rotatedTemplate, result, Imgproc.TM_CCOEFF_NORMED); Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1); // 找到最大匹配得分和位置 MinMaxLocResult mmr = Core.minMaxLoc(result); double score = mmr.maxVal; if (score >= minScore && score > maxScore) { maxScore = score; maxLoc = mmr.maxLoc; } // 更新旋转角度 angle += angleStep; } // 在原图像上标记匹配结果 if (maxLoc != null) { Point topLeft = new Point(maxLoc.x, maxLoc.y); Point bottomRight = new Point(topLeft.x + template.cols(), topLeft.y + template.rows()); Imgproc.rectangle(img, topLeft, bottomRight, new Scalar(0, 0, 255), 2); } // 显示匹配结果 HighGui.imshow("Result", img); HighGui.waitKey(); } } ```
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

thequitesunshine007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值