opencv模板匹配_opencv模板匹配
opencv模板匹配
模板匹配在图像处理中经常使⽤,该算法主要⽤于寻图像中与模板图像相同的区域。此外,也⽤于图像定位,通过模板匹配到指定的位置,然后进⾏后续的处理。
在进⾏模板匹配的时候,需要先制作模板,模板图像⼀般是从原始图像中取出⼀块图像区域作为模板。模板图像⼀定要⼩于待匹配的图像。在opencv中,提供了6种模板匹配的⽅式,即平⽅差匹配法(TM_SQDIFF)、 归⼀化平⽅差匹配法(TM_SQDIFF_NORMED)、相关匹配法(TM_CCORR)、归⼀化相关匹配法(TM_CCORR_NORMED)、系数匹配法(TM_CCOEFF)、归⼀化相关系数匹配法
(TM_CCOEFF_NORMED)。其中,前⾯两种匹配⽅式得到的匹配系数越⼩则模板与待匹配图像越匹配。后⾯两种的匹配系数越⼤越匹配。所以,在进⾏模板匹配的时候,要根据选择的匹配⽅式来确定最匹配的位置。不管哪种匹配⽅式,其实⽅法都很简单,就是让模板图像在待匹配图像上滑动,计算模板图像覆盖在待匹配图像上的⼀些参数值,如平⽅差,相关性等。记录下每次滑动后的这些值,然后寻最⼩值或最⼤值,得到该值在待匹配图像上的位置就是匹配的位置。
图1 模板匹配⽰意图
模板匹配是⼀种⽐较简单的算法。但是,该算法有⼀定的缺陷,⾸先,如果基于灰度图进⾏模板匹配,匹配的准确性不太好,因为实时采集的图像受到光照条件的变化,灰度值会发⽣变化。其次,该算法不具有旋转不变性,当图像有⼀定旋转⾓度的时候,与模板的匹配效果不好,这种匹配只适⽤于没有旋转或旋转⾓度很⼩的时候。最后,该算法的计算速度较慢,不太适合实时应⽤。
刚开始做图像处理的时候,⼏乎都会接触到模板匹配算法,但是。⽤过⼏次之后,就发现该算法好像不能得到想要的结果。这就是因为模板匹配算法有上⾯所提到的不⾜。但是,其实稍微修改⼀下,就可以解决很多问题。对于基于灰度值匹配不准确的问题,其实,⼀般不采⽤基于灰度值的匹配,⽽可以改为基于边界的匹配,这样的匹配准确率会好很多。对于计算速度慢的问题,⼀般不要直接图像和
模板图像进⾏匹配,⽽是将图像和模板图像先进⾏⾼斯⾦字塔向下采样,将图像缩⼩,然后再进⾏匹配,然后将匹配结果再进⾏⾼斯⾦字塔向上采样,这时再得到匹配的位置,这样的计算速度会提⾼很多。对于图像旋转的问题,这个算法不能够很好的处理,⼀种变通的处理⽅法是先制作不同⾓度的模板,但是这种⽅法由于需要匹配的模板太多,导致计算速度变慢。因此,⼀般在实时处理的地⽅不推荐采⽤这种⽅式,⽽应该采⽤具有旋转匹配功能的⽅式,在这⾥暂时不说,以后有机会再说。
下⾯以opencv的代码具体实现模板匹配。代码在opencv4.0和vs2015的c++实现,如果已经配置好了,只要到⼀张图,稍微修改⼀下模板图像位置就可以直接运⾏。代码中关键位置有注释。
#include"iostream"
#include"opencv2\opencv.hpp"
usingnamespace std;
usingnamespace cv;
int main(intargc, char** argv)
{
//读取⼀张图像
Mat src = imread("E:/img1.bmp", 0);
Mat gaussImg;
pyrDown(src, gaussImg);
namedWindow("原图",0);
imshow("原图", src);
//从原图中取出⼀块区域作为⽽模板图像
Mat templateImg = src(Range(200, 400),Range(300, 600));
namedWindow("模板图", 0);
imshow("模板图", templateImg);
//匹配结果矩阵的⼤⼩
int result_cols =ls - ls + 1;
int result_rows =ws - ws + 1;
Mat result = cv::Mat(result_cols,result_rows, CV_32FC1);
//进⾏模板匹配,选择的是TM_CCOEFF_NORMED⽅式
matchTemplate(src, templateImg, result, TM_CCOEFF_NORMED);
double minVal, maxVal;
Point minLoc, maxLoc,matchLoc;
//在匹配结果矩阵中查匹配的最⼤最⼩值以及最⼤最⼩值对应的位置
minMaxLoc(result, &minVal, &maxVal, &minLoc,&maxLoc, Mat());
matchLoc = maxLoc;
//将匹配结果矩形在原图上绘制出来
Mat srcRGB;
cvtColor(src, srcRGB, COLOR_GRAY2RGB);
rectangle(srcRGB, Rect(matchLoc.x, matchLoc.y, ws), Scalar(255,0, 0),3); namedWindow("匹配结果", 0);
imshow("匹配结果", srcRGB);
//基于边界的模板匹配,⾸先对图像进⾏边缘检测,这⾥采⽤canny算⼦进⾏边缘检测
Mat srcCannyResult;
Canny(src, srcCannyResult, 75, 170);
namedWindow("原图canny边界", 0);
imshow("原图canny边界", srcCannyResult);
//模板图与匹配图像采⽤图像的边缘检测算法和同样的参数
Mat tempCannyResult;
Canny(templateImg, tempCannyResult, 75, 170);
namedWindow("模板canny边界", 0);
imshow("模板canny边界", tempCannyResult);rectangle函数opencv
Mat borderResult = cv::Mat(result_cols,result_rows, CV_32FC1);
matchTemplate(srcCannyResult, tempCannyResult, borderResult, TM_CCOEFF_NORMED);
double borderMinVal,borderMaxVal;
Point borderMinLoc,borderMaxLoc, borderMtchLoc;
minMaxLoc(borderResult, &borderMinVal, &borderMaxVal,&borderMinLoc, &borderMaxLoc, Mat());
matchLoc = borderMaxLoc;
//绘制基于边缘的模板匹配结果,直接在边缘检测结果图像绘制矩形,也可以在原图上绘制,这⾥没有转成彩⾊图显⽰
rectangle(srcCannyResult, Rect(matchLoc.x,matchLoc.y, ls, ws), Scalar(255, 255, 255), 3); namedWindow("边缘匹配结果", 0);
imshow("边缘匹配结果", srcCannyResult);
waitKey(0);
}
图2 基于灰度值的模板匹配
图3 基于边界的模板匹配
在这⾥没有实现⾼斯⾦字塔采样后的匹配,⾼斯⾦字塔采样很简单,就两个函数:pyrDown和pyrUp函数。有兴趣的可以⾃⼰去实现。模板匹配算法还是很有⽤的,只是对于图像有旋转的情况下适应性不好,对于⼤部分没有旋转的时候,或者旋转⾓度很⼩的时候,利⽤该算法实现特定⽬标的定位是没有问题的。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论