前言
本案例要实现的功能是使用OpenCV中的matchTemplate实现多目标匹配。熟悉matchTemplate这个API的小伙伴都知道,仅仅单一使用matchTemplate的话只能实现单一目标匹配,而不能实现多目标匹配。那么接下来我们就一起看看如何使用matchTemplate实现多目标匹配吧。
一、图像预处理
首先加载测试图像与模板图像,如下图所示: 测试图像: 模板图像: 我们的最终目的是在测试图像中找到所有模板图像的物体,并把它框出来。
首先将图像灰度化、去噪
Mat src_gray, src_gaussian;
cvtColor(src, src_gray, COLOR_BGR2GRAY);
GaussianBlur(src_gray, src_gaussian, Size(3, 3), 0);
Mat temp_gray, temp_gaussian;
cvtColor(temp, temp_gray, COLOR_BGR2GRAY);
GaussianBlur(temp_gray, temp_gaussian, Size(3, 3), 0);
然后调用matchTemplate进行模板匹配,matchTemplate提供六种计算图像相似度的方法。 1、差值平方和匹配 CV_TM_SQDIFF —匹配结果越好,值越小(0) 2、标准化差值平方和匹配 CV_TM_SQDIFF_NORMED 3、相关匹配 CV_TM_CCORR —匹配结果越好,值越大;0表示匹配结果最差 4、标准相关匹配 CV_TM_CCORR_NORMED 5、相关匹配 CV_TM_CCOEFF —1:表示完全相同;0:表示完全不相同 6、标准相关匹配 CV_TM_CCOEFF_NORMED
在这里我使用的是标准相关匹配,结果如下面所示。
Mat result;
matchTemplate(src_gaussian, temp_gaussian, result, TM_CCOEFF_NORMED);
normalize(result, result, 0, 1, NORM_MINMAX);
如下图所示:即为我们使用matchTemplate及归一化得到的结果 使用minMaxLoc找到最大最小值,以及它们所在坐标。
double minVal, maxVal;
Point minLoc, maxLoc;
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
二、单目标匹配
rectangle(src, Rect(maxLoc.x, maxLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 5);
如图为单目标匹配结果,接下来看看多目标匹配是如何实现的。
三、多目标匹配
我们之前使用matchTemplate得到归一化之后的结果,我们需要的是使用3*3邻域非极大值抑制找到result中所有邻域最大值。
double quality = 0.88;
if (quality <= 0.0)quality = 0.0;
if (quality >= 1.0)quality = 1.0;
double thresh = maxVal * quality;
for (int i = 0; i < result.rows; i++)
{
for (int j = 0; j < result.cols; j++)
{
double val = result.at<float>(i, j);
if (val > thresh)
{
if (result.at<float>(i - 1, j - 1) < val &&
result.at<float>(i - 1, j) < val &&
result.at<float>(i - 1, j + 1) < val &&
result.at<float>(i, j - 1) < val &&
result.at<float>(i, j + 1) < val &&
result.at<float>(i + 1, j - 1) < val &&
result.at<float>(i + 1, j) < val &&
result.at<float>(i + 1, j + 1) < val)
{
rectangle(src, Rect(j, i, temp.cols, temp.rows), Scalar(0, 255, 0), 2);
char text[10];
float score = result.at<float>(i, j);
sprintf_s(text, "%.2f",score);
putText(src, text, Point(j, i), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0, 0, 255), 2);
}
}
}
}
1、 效果显示
如图,我们可以看到大部分的目标都找到了。我们可以通过控制quality 匹配质量来控制我们最终的匹配精度,quality 越大,匹配程度越高。
四、结果显示
在这里我做了点骚操作,将模板图像与测试图像放在一张新图像上。直接上代码
Mat canvas(Size(src.cols + temp.cols + 200, src.rows), CV_8UC3, Scalar::all(255));
src.copyTo(canvas(Rect(0, 0, src.cols, src.rows)));
rectangle(canvas, Rect(src.cols +40 , 50, 200, 80), Scalar(0,255,0), -1);
putText(canvas, tempname.substr(0, tempname.find(".")), Point(src.cols + 100 , 100), FONT_HERSHEY_SIMPLEX, 1.3, Scalar(0,0,255), 3);
temp.copyTo(canvas(Rect(src.cols + 100, 150, temp.cols, temp.rows)));
namedWindow("Demo", WINDOW_NORMAL);
imshow("Demo", canvas);
1、 效果显示
五、源码
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("test.jpg");
string tempname = "fox.jpg";
Mat temp = imread(tempname);
if (src.empty() || temp.empty())
{
cout << "No Image..." << endl;
system("pause");
return -1;
}
Mat src_gray, src_gaussian;
cvtColor(src, src_gray, COLOR_BGR2GRAY);
GaussianBlur(src_gray, src_gaussian, Size(3, 3), 0);
Mat temp_gray, temp_gaussian;
cvtColor(temp, temp_gray, COLOR_BGR2GRAY);
GaussianBlur(temp_gray, temp_gaussian, Size(3, 3), 0);
Mat result;
matchTemplate(src_gaussian, temp_gaussian, result, TM_CCOEFF_NORMED);
normalize(result, result, 0, 1, NORM_MINMAX);
double minVal, maxVal;
Point minLoc, maxLoc;
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
double quality = 0.88;
if (quality <= 0.0)quality = 0.0;
if (quality >= 1.0)quality = 1.0;
double thresh = maxVal * quality;
for (int i = 0; i < result.rows; i++)
{
for (int j = 0; j < result.cols; j++)
{
double val = result.at<float>(i, j);
if (val > thresh)
{
if (result.at<float>(i - 1, j - 1) < val &&
result.at<float>(i - 1, j) < val &&
result.at<float>(i - 1, j + 1) < val &&
result.at<float>(i, j - 1) < val &&
result.at<float>(i, j + 1) < val &&
result.at<float>(i + 1, j - 1) < val &&
result.at<float>(i + 1, j) < val &&
result.at<float>(i + 1, j + 1) < val)
{
rectangle(src, Rect(j, i, temp.cols, temp.rows), Scalar(0, 255, 0), 2);
char text[10];
float score = result.at<float>(i, j);
sprintf_s(text, "%.2f",score);
putText(src, text, Point(j, i), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0, 0, 255), 2);
}
}
}
}
Mat canvas(Size(src.cols + temp.cols + 200, src.rows), CV_8UC3, Scalar::all(255));
src.copyTo(canvas(Rect(0, 0, src.cols, src.rows)));
rectangle(canvas, Rect(src.cols +40 , 50, 200, 80), Scalar(0,255,0), -1);
putText(canvas, tempname.substr(0, tempname.find(".")), Point(src.cols + 100 , 100), FONT_HERSHEY_SIMPLEX, 1.3, Scalar(0,0,255), 3);
temp.copyTo(canvas(Rect(src.cols + 100, 150, temp.cols, temp.rows)));
namedWindow("Demo", WINDOW_NORMAL);
imshow("Demo", canvas);
waitKey(0);
system("pause");
return false;
}
总结
本文使用OpenCV C++多目标匹配,主要操作有以下几点。 1、图像预处理 2、matchTemplate模板匹配以及图像归一化 3、minMaxLoc计算图像最大最小值 4、3*3非极大值抑制寻找邻域最大值,极为目标
|