c++ OpenCV自带的模板匹配matchTemplate方法是不支持旋转的,也就是说当目标和模板有角度差异时匹配常常会失败,可能目标只是轻微的旋转,匹配分数就会下降很多,导致匹配精度下降甚至匹配出错。本文介绍基于matchTemplate + 旋转 实现多角度的模板匹配,返回匹配结果(斜矩形的端点、角度、匹配得分);
将模板图像旋转,旋转模版图像代码如下:
Mat ImageRotate(Mat image, double angle)
{
Mat newImg;
Point2f pt = Point2f((float)image.cols / 2, (float)image.rows / 2);
Mat M = getRotationMatrix2D(pt, angle, 1.0);
warpAffine(image, newImg, M, image.size());
return newImg;
}
从0~360°旋转角度依次匹配:
找到超过设定阈值的多个匹配位置:
完整处理逻辑如下:
void rotateMatch(Mat src, Mat model, double thresholdvalue, int numLevels = 0) {
struct MatchResult {
Point point[4];
double angle;
double score;
};
double startAngle = 0;
double endAngle = 360;
double firstStep = 30;
double secondStep = 10;
//对模板图像和待检测图像分别进行图像金字塔下采样
for (int i = 0; i < numLevels; i++) {
pyrDown(src, src, Size(src.cols / 2, src.rows / 2));
pyrDown(model, model, Size(model.cols / 2, model.rows / 2));
}
Mat rotatedImg, result;
//double score = -1;
vector<double> scorevec;
vector<Point> locationvec;
vector<double> anglevec;
bool isSecond = false;
while (true) {
for (double curAngle = startAngle; curAngle < endAngle; curAngle += firstStep) {
rotatedImg = ImageRotate(model, curAngle);
matchTemplate(src, rotatedImg, result, TM_CCOEFF_NORMED);
double minval, maxval;
Point minloc, maxloc;
while (true) {
minMaxLoc(result, &minval, &maxval, &minloc, &maxloc);
if (maxval > thresholdvalue)
{
locationvec.push_back(maxloc);
scorevec.push_back(maxval);
anglevec.push_back(curAngle);
rectangle(result, Point(maxloc.x-5, maxloc.y - 5), Point(maxloc.x + model.cols+5, maxloc.y + model.rows+5), Scalar(0), -1);
}
else {
break;
}
}
}
break;
}
if (scorevec.size()<1) {
cout << "无匹配" << endl;
return;
}
for (int i = 0; i < locationvec.size();i++) {
Point finalPoint = Point(locationvec[i].x * pow(2, numLevels), locationvec[i].y * pow(2, numLevels));
vector<Point> points = GetRotatePoints(Size(model.cols * pow(2, numLevels), model.rows * pow(2, numLevels)), anglevec[i]);
vector<MatchResult> matchResult;
MatchResult matchResulttmp;
for (int j = 0; j < points.size(); j++)
{
points[j].x += finalPoint.x;
points[j].y += finalPoint.y;
matchResulttmp.point[j] = points[j];
}
matchResulttmp.angle = anglevec[i];
matchResulttmp.score = scorevec[i];
matchResult.push_back(matchResulttmp);
for (int i = 0; i < 4; ++i)
{
cv::line(src, points[i % 4], points[(i + 1) % 4], cv::Scalar(0, 0, 255), 2);
}
cout << anglevec[i] << endl;
cout << scorevec[i] << endl;
}
imshow("原始图", src);
}
终端输出如下: