本文介绍多角度的模板匹配,正常模板匹配详情见

https://blog.51cto.com/u_15996251/11117111

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°旋转角度依次匹配:

C++ 多角度模板匹配_opencv

找到超过设定阈值的多个匹配位置:

C++ 多角度模板匹配_多角度匹配_02

完整处理逻辑如下:

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

}

终端输出如下:

C++ 多角度模板匹配_opencv_03