OpenCV 4.x API 详解与C++实例-物体检测

第十二节 物体检测

Opencv的imgproc模块提供了matchTemplate模板匹配函数,该函数计算模板与待测图片的重叠区域的相似度。

1、cv::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...w1y=0...h1

函数完成比较后,可以使用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,yT(x,y)2x,yI(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))2x,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,yT(x,y)2x,yI(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))2x,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/(wh)x,yT(x,y)I(x+x,y+y)=I(x+x,y+y)1/(wh)x,yI(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,yM(x,y)1x,y(T(x,y)M(x,y)))I(x+x,y+y)=M(x,y)(I(x+x,y+y)x,yM(x,y)1x,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,yT(x,y)2x,yI(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 <iostream>
#include <opencv2/opencv.hpp>

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;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/wujuxKkoolerter/article/details/113068846
今日推荐