Opencv的imgproc模块提供了matchTemplate模板匹配函数,该函数计算模板与待测图片的重叠区域的相似度。
将模板与重叠的图像区域进行比较。
void cv::matchTemplate(InputArray image,InputArray templ,OutputArray result,int method,InputArray mask = noArray())
该函数图像中滑动,并使用指定的方法将大小为 w × h w×h w×h的重叠块与模板进行比较,并将比较结果存储在result中。 TemplateMatchModes描述了可用比较方法的公式( I I I表示图像, T T T模板, R R R结果, M M M表示可选蒙版)。 对模板和/或图像块进行求和: x ′ = 0... w − 1 , y ′ = 0... h − 1 x'= 0 ... w-1,y'= 0 ... h-1 x′=0...w−1,y′=0...h−1。
函数完成比较后,可以使用minMaxLoc函数找到最佳匹配项,作为全局最小值(使用TM_SQDIFF时)或最大值(使用TM_CCORR或TM_CCOEFF时)。 在彩色图像的情况下,分子的模板求和和分母的每个求和在所有通道上进行,每个通道使用单独的平均值。 即,该功能可以获取颜色模板和彩色图像。 结果仍然是单通道图像,更易于分析。
参数如下:
参数名称 | 参数描述 |
---|---|
image | 输入所要匹配的图像,必须是8位或32位单精度。 |
templ | 搜索模板。它必须不大于源图像并且具有相同的数据类型。 |
result | 比较结果图。 它必须是单通道32位浮点。 如果image是W×H并且templ是w×h,那么结果是(W-w + 1)×(H-h + 1)。 |
method | 比较方法,请参考 TemplateMatchModes |
mask | 可选的掩膜。 它的大小必须与templ相同。它必须具有与模板相同的通道数,或者只能具有一个通道,然后将其用于所有模板和图像通道。如果数据类型为CV_8U,则掩码将被解释为二进制掩码,这意味着仅使用掩码为非零的元素并且保持不变。与实际掩码值无关(权重等于1)。对于数据tpye [CV_32F],掩码值用作权重。确切的公式记录在TemplateMatchModes中。 |
TemplateMatchModes的详细说明如下:
方法名称 | 描述 |
---|---|
TM_SQDIFF | 不带掩膜: R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) − I ( x + x ′ , y + y ′ ) ) 2 R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2 R(x,y)=∑x′,y′(T(x′,y′)−I(x+x′,y+y′))2 ;有掩膜: R ( x , y ) = ∑ x ′ , y ′ ( ( T ( x ′ , y ′ ) − I ( x + x ′ , y + y ′ ) ) ⋅ M ( x ′ , y ′ ) ) 2 R(x,y)= \sum _{x',y'} \left( (T(x',y')-I(x+x',y+y')) \cdot M(x',y') \right)^2 R(x,y)=∑x′,y′((T(x′,y′)−I(x+x′,y+y′))⋅M(x′,y′))2 |
TM_SQDIFF_NORMED | 不带掩膜: R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) − I ( x + x ′ , y + y ′ ) ) 2 ∑ x ′ , y ′ T ( x ′ , y ′ ) 2 ⋅ ∑ x ′ , y ′ I ( x + x ′ , y + y ′ ) 2 R(x,y)= \frac{\sum_{x',y'} (T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum_{ x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} R(x,y)=∑x′,y′T(x′,y′)2⋅∑x′,y′I(x+x′,y+y′)2∑x′,y′(T(x′,y′)−I(x+x′,y+y′))2;有掩膜: R ( x , y ) = ∑ x ′ , y ′ ( ( T ( x ′ , y ′ ) − I ( x + x ′ , y + y ′ ) ) ⋅ M ( x ′ , y ′ ) ) 2 ∑ x ′ , y ′ ( T ( x ′ , y ′ ) ⋅ M ( x ′ , y ′ ) ) 2 ⋅ ∑ x ′ , y ′ ( I ( x + x ′ , y + y ′ ) ⋅ M ( x ′ , y ′ ) ) 2 R(x,y)= \frac{\sum _{x',y'} \left( (T(x',y')-I(x+x',y+y')) \cdot M(x',y') \right)^2}{\sqrt{\sum_{x',y'} \left( T(x',y') \cdot M(x',y') \right)^2 \cdot \sum_{x',y'} \left( I(x+x',y+y') \cdot M(x',y') \right)^2}} R(x,y)=∑x′,y′(T(x′,y′)⋅M(x′,y′))2⋅∑x′,y′(I(x+x′,y+y′)⋅M(x′,y′))2∑x′,y′((T(x′,y′)−I(x+x′,y+y′))⋅M(x′,y′))2 |
TM_CCORR | 不带掩膜: R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) ⋅ I ( x + x ′ , y + y ′ ) ) R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y')) R(x,y)=∑x′,y′(T(x′,y′)⋅I(x+x′,y+y′));有掩膜: R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) ⋅ I ( x + x ′ , y + y ′ ) ⋅ M ( x ′ , y ′ ) 2 ) R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y') \cdot M(x',y') ^2) R(x,y)=∑x′,y′(T(x′,y′)⋅I(x+x′,y+y′)⋅M(x′,y′)2) |
TM_CCORR_NORMED | 不带掩膜: R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) ⋅ I ( x + x ′ , y + y ′ ) ) ∑ x ′ , y ′ T ( x ′ , y ′ ) 2 ⋅ ∑ x ′ , y ′ I ( x + x ′ , y + y ′ ) 2 R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y'))}{\sqrt{ \sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} R(x,y)=∑x′,y′T(x′,y′)2⋅∑x′,y′I(x+x′,y+y′)2∑x′,y′(T(x′,y′)⋅I(x+x′,y+y′));有掩膜: R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) ⋅ I ( x + x ′ , y + y ′ ) ⋅ M ( x ′ , y ′ ) 2 ) ∑ x ′ , y ′ ( T ( x ′ , y ′ ) ⋅ M ( x ′ , y ′ ) ) 2 ⋅ ∑ x ′ , y ′ ( I ( x + x ′ , y + y ′ ) ⋅ M ( x ′ , y ′ ) ) 2 R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y') \cdot M(x',y')^2)}{\sqrt{\sum_{x',y'} \left( T(x',y') \cdot M(x',y') \right)^2 \cdot \sum_{x',y'} \left( I(x+x',y+y') \cdot M(x',y') \right)^2}} R(x,y)=∑x′,y′(T(x′,y′)⋅M(x′,y′))2⋅∑x′,y′(I(x+x′,y+y′)⋅M(x′,y′))2∑x′,y′(T(x′,y′)⋅I(x+x′,y+y′)⋅M(x′,y′)2) |
TM_CCOEFF | 不带掩膜: R ( x , y ) = ∑ x ′ , y ′ ( T ′ ( x ′ , y ′ ) ⋅ I ′ ( x + x ′ , y + y ′ ) ) R(x,y)= \sum _{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) R(x,y)=∑x′,y′(T′(x′,y′)⋅I′(x+x′,y+y′));其中: T ′ ( x ′ , y ′ ) = T ( x ′ , y ′ ) − 1 / ( w ⋅ h ) ⋅ ∑ x ′ ′ , y ′ ′ T ( x ′ ′ , y ′ ′ ) I ′ ( x + x ′ , y + y ′ ) = I ( x + x ′ , y + y ′ ) − 1 / ( w ⋅ h ) ⋅ ∑ x ′ ′ , y ′ ′ I ( x + x ′ ′ , y + y ′ ′ ) \begin{array}{l} T'(x',y')=T(x',y') - 1/(w \cdot h) \cdot \sum _{ x'',y''} T(x'',y'') \\ I'(x+x',y+y')=I(x+x',y+y') - 1/(w \cdot h) \cdot \sum _{x'',y''} I(x+x'',y+y'') \end{array} T′(x′,y′)=T(x′,y′)−1/(w⋅h)⋅∑x′′,y′′T(x′′,y′′)I′(x+x′,y+y′)=I(x+x′,y+y′)−1/(w⋅h)⋅∑x′′,y′′I(x+x′′,y+y′′);有掩膜: T ′ ( x ′ , y ′ ) = M ( x ′ , y ′ ) ⋅ ( T ( x ′ , y ′ ) − 1 ∑ x ′ ′ , y ′ ′ M ( x ′ ′ , y ′ ′ ) ⋅ ∑ x ′ ′ , y ′ ′ ( T ( x ′ ′ , y ′ ′ ) ⋅ M ( x ′ ′ , y ′ ′ ) ) ) I ′ ( x + x ′ , y + y ′ ) = M ( x ′ , y ′ ) ⋅ ( I ( x + x ′ , y + y ′ ) − 1 ∑ x ′ ′ , y ′ ′ M ( x ′ ′ , y ′ ′ ) ⋅ ∑ x ′ ′ , y ′ ′ ( I ( x + x ′ ′ , y + y ′ ′ ) ⋅ M ( x ′ ′ , y ′ ′ ) ) ) \begin{array}{l} T'(x',y')=M(x',y') \cdot \left( T(x',y') - \frac{1}{\sum _{x'',y''} M(x'',y'')} \cdot \sum _{x'',y''} (T(x'',y'') \cdot M(x'',y'')) \right) \\ I'(x+x',y+y')=M(x',y') \cdot \left( I(x+x',y+y') - \frac{1}{\sum _{x'',y''} M(x'',y'')} \cdot \sum _{x'',y''} (I(x+x'',y+y'') \cdot M(x'',y'')) \right) \end{array} T′(x′,y′)=M(x′,y′)⋅(T(x′,y′)−∑x′′,y′′M(x′′,y′′)1⋅∑x′′,y′′(T(x′′,y′′)⋅M(x′′,y′′)))I′(x+x′,y+y′)=M(x′,y′)⋅(I(x+x′,y+y′)−∑x′′,y′′M(x′′,y′′)1⋅∑x′′,y′′(I(x+x′′,y+y′′)⋅M(x′′,y′′))) |
TM_CCOEFF_NORMED | R ( x , y ) = ∑ x ′ , y ′ ( T ′ ( x ′ , y ′ ) ⋅ I ′ ( x + x ′ , y + y ′ ) ) ∑ x ′ , y ′ T ′ ( x ′ , y ′ ) 2 ⋅ ∑ x ′ , y ′ I ′ ( x + x ′ , y + y ′ ) 2 R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} } R(x,y)=∑x′,y′T′(x′,y′)2⋅∑x′,y′I′(x+x′,y+y′)2∑x′,y′(T′(x′,y′)⋅I′(x+x′,y+y′)) |
注意:TM_SQDIFF_NORMED,TM_CCORR_NORMED,TM_CCOEFF_NORMED是标准化的匹配,得到的最大值,最小值范围在0~1之间,其它则需要自己对结果矩阵归一化。
#include
#include
using namespace std;
int main()
{
// 读取图片
cv::Mat src = cv::imread("images/chars.png");
if(src.empty()){
cerr << "cannot read image1.\n";
return EXIT_FAILURE;
}
// 读取模板
cv::Mat temp = cv::imread("images/char-d.png");
if(temp.empty()){
cerr << "cannot read image2.\n";
return EXIT_FAILURE;
}
// 转换成灰度图像
cv::Mat srcGray,tempGray,srcGrayF32,tempF32;
cv::cvtColor(temp,tempGray,cv::COLOR_BGR2GRAY);
cv::cvtColor(src,srcGray,cv::COLOR_BGR2GRAY);
// 转换成浮点数据类型
srcGray.convertTo(srcGrayF32,CV_32FC1);
tempGray.convertTo(tempF32,CV_32FC1);
// 执行模板匹配
cv::Mat result;
cv::matchTemplate(srcGrayF32,tempF32,result,cv::TM_CCOEFF);
// 查找匹配位置
double minVal;
cv::Point minLoc,maxLoc;
cv::minMaxLoc(result,&minVal,NULL,&minLoc,NULL);
// 绘制匹配位置
cv::rectangle(src,minLoc,cv::Point(minLoc.x+ temp.cols,minLoc.y+temp.rows), cv::Scalar(255, 0, 0), 2);
// 显示
cv::imshow("src",src);
cv::imshow("temp",temp);
cv::waitKey();
cv::destroyAllWindows();
return 0;
}