概述
在人工智能(AI)的研究领域中,模板匹配不仅是一个重要的研究课题,也是解决图像处理中核心问题——定位兴趣区域的关键方法之一。通过模板匹配,可以准确地识别和定位给定图像中的特定对象。这项技术在对象检测、跟踪、监控、医学成像以及图像拼接等多个领域都有着广泛的应用。
模板匹配
模板匹配主要涉及两个核心要素:源图像和模板图像。源图像是期望在其中寻找模板图像匹配的图像,而模板图像则是用于与源图像的子图像进行比较的参考图像。
源图像:
模板图像:
在图像匹配算法可分为两大类别,基于模板的匹配和基于特征的匹配各具特色。
1.基于模板的方法,也被称作区域匹配法,适用于模板图像在图像中缺乏显著特征的情况。这种方法直接处理像素值,通过计算图像与模板的强度值来衡量匹配程度。
2.基于特征的方法则适用于源图像和模板图像在特征和控制点上有较高一致性的情况。此时,特征可以是点、曲线或表面模型,用于执行模板匹配。
基于模板
传统的模板匹配通过滑动模板图像与源图像进行对比。模板图像逐像素地在源图像上移动,通过计算重叠区域的相似性数值来寻找匹配。通常,两幅图像会被转换成二值或黑白图像,然后应用如归一化交叉相关、交叉相关和平方差和等匹配技术。
然而,基于模板的方法在处理尺度变化时面临挑战。源图像或模板图像的尺寸变化会影响匹配算法的效果。为了解决这个问题,一个常用的技巧是将模板图像调整到多个尺度,然后与源图像进行比较。在遍历所有尺度后,选择具有最高相关系数的区域作为“匹配”区域。但是,这种方法难以解决旋转不变性问题。为此,Kim, Hae & Araújo, Sidnei(2007年)提出了Ciratefi算法,该算法通过改进蛮力算法——即在每个角度旋转模板图像——来解决旋转问题。Ciratefi算法的计算速度比蛮力算法快400倍,且结果相同。
实现代码:
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
bool use_mask;
Mat img; Mat templ; Mat mask; Mat result;
const char* image_window = "Source Image";
const char* result_window = "Result window";
int match_method;
int max_Trackbar = 5;
void MatchingMethod( int, void* );
const char* keys =
"{ help h| | Print help message. }"
"{ @input1 | Template_Matching_Original_Image.jpg | image_name }"
"{ @input2 | Template_Matching_Template_Image.jpg | template_name }"
"{ @input3 | | mask_name }";
int main( int argc, char** argv )
{
CommandLineParser parser( argc, argv, keys );
samples::addSamplesDataSearchSubDirectory( "doc/tutorials/imgproc/histograms/template_matching/images" );
img = imread( samples::findFile( parser.get<String>("@input1") ) );
templ = imread( samples::findFile( parser.get<String>("@input2") ), IMREAD_COLOR );
if(argc > 3) {
use_mask = true;
mask = imread(samples::findFile( parser.get<String>("@input3") ), IMREAD_COLOR );
}
if(img.empty() || templ.empty() || (use_mask && mask.empty()))
{
cout << "Can't read one of the images" << endl;
return EXIT_FAILURE;
}
namedWindow( image_window, WINDOW_AUTOSIZE );
namedWindow( result_window, WINDOW_AUTOSIZE );
const char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED";
createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod );
MatchingMethod( 0, 0 );
waitKey(0);
return EXIT_SUCCESS;
}
void MatchingMethod( int, void* )
{
Mat img_display;
img.copyTo( img_display );
int result_cols = img.cols - templ.cols + 1;
int result_rows = img.rows - templ.rows + 1;
result.create( result_rows, result_cols, CV_32FC1 );
bool method_accepts_mask = (TM_SQDIFF == match_method || match_method == TM_CCORR_NORMED);
if (use_mask && method_accepts_mask)
{ matchTemplate( img, templ, result, match_method, mask); }
else
{ matchTemplate( img, templ, result, match_method); }
normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );
double minVal; double maxVal; Point minLoc; Point maxLoc;
Point matchLoc;
minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
if( match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED )
{ matchLoc = minLoc; }
else
{ matchLoc = maxLoc; }
rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
imshow( image_window, img_display );
imshow( result_window, result );
return;
}
基于特征的方法
特征检测与匹配是许多计算机视觉都有应用,例如运动结构、图像检索、物体检测等。
特征检测与匹配的应用:
- 自动化物体跟踪
- 计算视差的点匹配
- 立体校准(基础矩阵估计)
- 基于运动的分割
- 识别
- 三维物体重建
- 机器人导航
- 图像检索和索引
特征:
特征是与解决特定应用相关的计算任务相关的信息。特征可能是图像中的特定结构,如点、边缘或物体。特征也可能是应用于图像的一般邻域操作或特征检测的结果。特征可以分为两大类:
- 图像中特定位置的特征,如山峰、建筑物角落、门道或形状有趣的雪块。这些局部化的特征通常称为关键点特征(或角点),通常通过围绕点位置的像素块的外观来描述。
- 可以根据其方向和局部外观(边缘轮廓)进行匹配的特征称为边缘,它们也可以作为图像序列中物体边界和遮挡事件的良好指示。
特征检测与匹配的主要组成部分:
- 检测:识别兴趣点
- 描述:每个特征点周围的局部外观以某种方式描述,理想情况下在光照、平移、尺度和平面旋转变化下是不变的。我们通常为每个特征点得到一个描述符向量。
兴趣点:
兴趣点或特征点是纹理表达丰富的点。兴趣点是物体边界方向突然改变的点或两条或多条边缘段的交点。
兴趣点的特性:
- 它在图像空间中有明确定义的位置或很好地局部化。
- 它在图像域的局部和全局扰动下稳定,如光照/亮度变化,以便可以可靠地计算兴趣点,并具有高度的重复性。
- 应提供有效的检测。
可能的方法:
- 基于图像的亮度(通常通过图像导数)。
- 基于边界提取(通常通过边缘检测和曲率分析)。
识别算法:
- 哈里斯角
- SIFT(尺度不变特征变换)
- SURF(加速稳健特征)
- FAST(加速段测试特征)
- ORB(定向FAST和旋转BRIEF)
特征描述符:
特征描述符是一种算法,它接受一张图像并输出特征描述符/特征向量。特征描述符将有趣的信息编码成一系列数字,并作为一种数值“指纹”,可以用来区分一个特征与另一个特征。
理想情况下,这些信息在图像变换下是不变的,因此即使图像以某种方式变换,我们也可以再次找到该特征。在检测到兴趣点后,我们继续为每个兴趣点计算描述符。描述符可以分为两类:
- 局部描述符:它是点的局部邻域的紧凑表示。局部描述符试图仅在点周围的局部邻域中模仿形状和外观,因此在匹配方面非常适用。
- 全局描述符:全局描述符描述整个图像。它们通常不太稳健,因为图像的一部分变化可能会导致它失败,因为它会影响生成的描述符。
算法:
- SIFT(尺度不变特征变换)
- SURF(加速稳健特征)
- BRISK(二进制稳健不变可扩展关键点)
- BRIEF(二进制稳健独立基本特征)
- ORB(定向FAST和旋转BRIEF)
特征匹配:
特征匹配或通常的图像匹配,是许多计算机视觉应用的一部分,如图像注册、相机校准和物体识别,其任务是在两个相同场景/对象的图像之间建立对应关系。图像匹配的常见方法包括从图像数据中检测一组兴趣点,每个点都与图像描述符相关联。一旦从两个或多个图像中提取了特征及其描述符,下一步就是在这些图像之间建立一些初步的特征匹配。
通常,基于兴趣点的匹配方法的性能取决于底层兴趣点的特性和相关图像描述符的选择。因此,应使用适合图像内容的检测器和描述符在应用程序中。例如,如果图像包含细菌细胞,则应使用斑点检测器而不是角点检测器。但是,如果图像是城市的航拍图,则使用角点检测器适合找到人造结构。此外,选择一个能够解决图像退化的检测器和描述符非常重要。
算法:
- 暴力匹配器
- FLANN(快速近似最近邻库)匹配器
特征检测与匹配算法:
- 找到一组独特的关键点
- 为每个关键点定义一个区域
- 提取并标准化区域内容
- 从标准化区域计算局部描述符
- 匹配局部描述符