【从零学习OpenCV 4】图像模板匹配
- 2019 年 12 月 24 日
- 筆記
经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《从零学习OpenCV 4》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。
前面我们通过图像直方图反向投影的方式在图像中寻找模板图像,由于直方图不能直接反应图像的纹理,因此如果两张不同模板图像具有相同的直方图分布特性,那么在同一张图中对这两张模板图像的直方图进行反向投影,最终结果将不具有参考意义。因此,我们在图像中寻找模板图像时,可以直接通过比较图像像素的形式来搜索是否存在相同的内容,这种通过比较像素灰度值来寻找相同内容的方法叫做图像的模板匹配。
模板匹配常用于在一幅图像中寻找特定内容的任务中。由于模板图像的尺寸小于待匹配图像的尺寸,同时又需要比较两张图像中的每一个像素的灰度值,因此常采用在待匹配图像中选择与模板相同尺寸的滑动窗口,通过比较滑动窗口与模板的相似程度,判断待匹配图像中是否含有与模板图像相同的内容,其原理如图4-11所示。
图4-11 模板匹配示意图
在图4-11中,右侧4×4的图像是模板图像,每个像素中的数字是该像素的灰度值,左侧8×8图像是待匹配图像,模板匹配的流程如下:
Step1:在待匹配图像中选取与模板尺寸大小相同的滑动窗口,如图4-11中的阴影区域所示。
Step2:比较滑动窗口中每个像素与模板中对应像素灰度值的关系,计算模板与滑动窗口的相似性。
Step3:将滑动窗口从左上角开始先向右滑动,滑动到最右边后向下滑动一行,从最左侧重新开始滑动,记录每一次移动后计算的模板与滑动窗口的相似性。
Step4:比较所有位置的相似性,选择相似性最大的滑动窗口作为备选匹配结果。
OpenCV 4中提供了用于图像模板匹配的函数matchTemplate(),该函数能够实现模板匹配过程中图像与模板相似性的计算,在代码清单4-12中给出了函数原型。
代码清单4-12 matchTemplate()函数原型 1. void cv::matchTemplate(InputArray image, 2. InputArray templ, 3. OutputArray result, 4. int method, 5. InputArray mask = noArray() 6. )
- image:待模板匹配的原图像,图像数据类型为CV_8U和CV_32F两者中的一个。
- templ:模板图像,需要与image具有相同的数据类型,但是尺寸不能大于image。
- result:模板匹配结果输出图像,图像数据类型为CV_32F。如果image的尺寸为W×H,模板图像尺寸为w×h,则输出图像的尺寸为(W-w+1)×(H-h+1)。
- method:模板匹配方法标志,可选择参数及含义在表4-3中给出。
- mask:匹配模板的掩码,必须与模板图像具有相同的数据类型和尺寸,默认情况下不设置,目前仅支持在TM_SQDIFF和TM_CCORR_NORMED这两种匹配方法时使用。
该函数同时支持灰度图像和彩色图像两种图像的模板匹配。函数前两个参数为输入的原图像和模板图像,由于是在原图像中搜索是否存在与模板图像相同的内容,因此需要模板图像的尺寸小于原图像,并且两者必须具有相同的数据类型。第三个参数为相似性矩阵,滑动窗口与模板的相似性系数存放在滑动窗口左上角第一个像素处,因此输出的相似性矩阵尺寸要小于原图像的尺寸,如果image的尺寸为W×H,模板图像尺寸为w×h,则输出图像的尺寸为(W-w+1)×(H-h+1)。因为在模板匹配中原图像不需要进行尺寸的外延,所以滑动窗口左上角可以移动的范围要小于原图像的尺寸。无论输入的是彩色图像还是灰度图像,函数输出结果都是单通道矩阵。了解相似性系数记录的方式便于寻找到与模板最相似的滑动窗口,继而在原图中标记出与模板相同的位置。函数第四个参数是滑动窗口与模板相似性系数的计算方式,OpenCV 4提供了多种计算方法,所有可以选择的标志参数在表4-3中给出,接下来对每一种方法进行详细介绍。
表4-3 matchTemplate()函数模板匹配方法选择标志参数
标志参数 |
简记 |
作用 |
---|---|---|
TM_SQDIFF |
0 |
平方差匹配法 |
TM_SQDIFF_NORMED |
1 |
归一化平方差匹配法 |
TM_CCORR |
2 |
相关匹配法 |
TM_CCORR_NORMED |
3 |
归一化相关匹配法 |
TM_CCOEFF |
4 |
系数匹配法 |
TM_CCOEFF_NORMED |
5 |
归一化相关系数匹配法 |
1
01
TM_SQDIFF
该方法名为平方差匹配法,计算的公式如式(6.9)所示,这种方法利用平方差来进行匹配,当模板与滑动窗口完全匹配时计算数值为0,两者匹配度越低计算数值越大。
1
02
TM_SQDIFF_NORMED
该方法名为归一化平方差匹配方法,计算公式如式(6.10)所示,这种方法是将平方差方法进行归一化,使得输入结果缩放到了0到1之间,当模板与滑动窗口完全匹配时计算数值为0,两者匹配度越低计算数值越大。
(6.10)
1
03
TM_CCORR
该方法名为相关匹配法,计算公式如式(6.11)所示,这类方法采用模板和图像间的乘法操作,所以数值越大表示匹配效果越好,0表示最坏的匹配结果。
(6.11)
1
04
TM_CCORR_NORMED
该方法名为归一化相关匹配法,计算公式如式(6.12)所示,这种方法是将相关匹配法进行归一化,使得输入结果缩放到了0到1之间,当模板与滑动窗口完全匹配时计算数值为1,两者完全不匹配时计算结果为0。
(6.12)
1
05
TM_CCOEFF
该方法名为系数匹配法,计算公式如式(6.13)所示,这种方法采用相关匹配方法对模板减去均值的结果和原图像减去均值的结果进行匹配,这种方法可以很好的解决模板图像和原图像之间由于亮度不同而产生的影响。该方法中模板与滑动窗口匹配度越高计算数值越大,匹配度越低计算数值越小,并且该方法计算结果可以为负数。
(6.13)
其中:
(6.14)
1
05
TM_CCOEFF_NORMED
该方法名为归一化系数匹配法,计算公式如式(6.15)所示,这种方法将系数匹配方法进行归一化,使得输入结果缩放到了1到-1之间,当模板与滑动窗口完全匹配时计算数值为1,当两者完全不匹配时计算结果为-1。
(6.15)
了解不同的计算相似性方法时,重点需要知道在每种方法中最佳匹配结果的数值应该是较大值还是较小值,由于matchTemplate()函数的输出结果是存有相关性系数的矩阵,因此需要通过minMaxLoc()函数去寻找输入矩阵中的最大值或者最小值,进而确定模板匹配的结果。
通过寻找输出矩阵的最大值或者最小值得到的只是一个像素点,需要以该像素点为矩形区域的左上角,绘制与模板图像同尺寸的矩形框,标记出最终匹配的结果。为了了解图像模板匹配相关函数的使用方法,在代码清单4-13中给出了在彩色图像中进行模板匹配的示例程序。程序中采用TM_CCOEFF_NORMED方法计算相关性系数,通过minMaxLoc()函数寻找相关性系数中的最大值,确定最佳匹配值的像素点坐标,之后在原图中绘制出与模板最佳匹配区域的范围,程序的运行结果在图4-12中给出。
代码清单4-13 myMatchTemplate.cpp图像的模板匹配 1. #include <opencv2opencv.hpp> 2. #include <iostream> 3. 4. using namespace cv; 5. using namespace std; 6. 7. int main() 8. { 9. Mat img = imread("lena.png"); 10. Mat temp = imread("lena_face.png"); 11. if (img.empty() || temp.empty()) 12. { 13. cout << "请确认图像文件名称是否正确" << endl; 14. return -1; 15. } 16. Mat result; 17. matchTemplate(img, temp, result, TM_CCOEFF_NORMED);//模板匹配 18. double maxVal, minVal; 19. Point minLoc, maxLoc; 20. //寻找匹配结果中的最大值和最小值以及坐标位置 21. minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc); 22. //绘制最佳匹配区域 23. rectangle(img,cv::Rect(maxLoc.x,maxLoc.y,temp.cols,temp.rows),Scalar(0,0,255),2); 24. imshow("原图", img); 25. imshow("模板图像", temp); 26. imshow("result", result); 27. waitKey(0); 28. return 0; 29. }
图4-12 myMatchTemplate.cpp程序运行结果