使用 OpenCV 进行角度和尺度不变模板匹配 [英] Angle and Scale Invariant template matching using OpenCV

查看:210
本文介绍了使用 OpenCV 进行角度和尺度不变模板匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

函数将模板图像从 0 度旋转到 180 度(或最多 360 度)以搜索源图像中所有相关匹配项(所有角度),即使比例不同.

Function rotates the template image from 0 to 180 (or upto 360) degrees to search all related matches(in all angles) in source image even with different scale.

该函数是用 OpenCV C 接口编写的.当我尝试将它移植到 openCV C++ interface 时,我遇到了很多错误.有人请帮我将它移植到 OpenCV C++ 接口.

The function had been written in OpenCV C interface. When I tried to port it to openCV C++ interface , I am getting lot of errors. Some one please help me to port it to OpenCV C++ interface.

  void TemplateMatch()
  {

    int i, j, x, y, key;
    double minVal;
    char windowNameSource[] = "Original Image";
    char windowNameDestination[] = "Result Image";
    char windowNameCoefficientOfCorrelation[] = "Coefficient of Correlation Image";
     CvPoint minLoc;
     CvPoint tempLoc;

     IplImage *sourceImage = cvLoadImage("template_source.jpg", CV_LOAD_IMAGE_ANYDEPTH         | CV_LOAD_IMAGE_ANYCOLOR);
     IplImage *templateImage = cvLoadImage("template.jpg", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);


   IplImage *graySourceImage = cvCreateImage(cvGetSize(sourceImage), IPL_DEPTH_8U, 1); 
   IplImage *grayTemplateImage =cvCreateImage(cvGetSize(templateImage),IPL_DEPTH_8U,1);
   IplImage *binarySourceImage = cvCreateImage(cvGetSize(sourceImage), IPL_DEPTH_8U, 1); 
  IplImage *binaryTemplateImage = cvCreateImage(cvGetSize(templateImage), IPL_DEPTH_8U, 1); 
  IplImage *destinationImage = cvCreateImage(cvGetSize(sourceImage), IPL_DEPTH_8U, 3); 

  cvCopy(sourceImage, destinationImage);

  cvCvtColor(sourceImage, graySourceImage, CV_RGB2GRAY);
  cvCvtColor(templateImage, grayTemplateImage, CV_RGB2GRAY);

  cvThreshold(graySourceImage, binarySourceImage, 200, 255, CV_THRESH_OTSU );
  cvThreshold(grayTemplateImage, binaryTemplateImage, 200, 255, CV_THRESH_OTSU);

  int templateHeight = templateImage->height;
  int templateWidth = templateImage->width;

 float templateScale = 0.5f;

  for(i = 2; i <= 3; i++) 
   {

    int tempTemplateHeight = (int)(templateWidth * (i * templateScale));
    int tempTemplateWidth = (int)(templateHeight * (i * templateScale));

    IplImage *tempBinaryTemplateImage = cvCreateImage(cvSize(tempTemplateWidth,                  tempTemplateHeight), IPL_DEPTH_8U, 1);

    // W - w + 1, H - h + 1

    IplImage *result = cvCreateImage(cvSize(sourceImage->width - tempTemplateWidth + 1,      sourceImage->height - tempTemplateHeight + 1), IPL_DEPTH_32F, 1);

    cvResize(binaryTemplateImage, tempBinaryTemplateImage, CV_INTER_LINEAR);
    float degree = 20.0f;
  for(j = 0; j <= 9; j++) 
    {

     IplImage *rotateBinaryTemplateImage = cvCreateImage(cvSize(tempBinaryTemplateImage-  >width, tempBinaryTemplateImage->height), IPL_DEPTH_8U, 1);

       //cvShowImage(windowNameSource, tempBinaryTemplateImage);  
      //cvWaitKey(0);             

        for(y = 0; y < tempTemplateHeight; y++)
          {

         for(x = 0; x < tempTemplateWidth; x++)
          {
            rotateBinaryTemplateImage->imageData[y * tempTemplateWidth + x] = 255;

          }         
          }


       for(y = 0; y < tempTemplateHeight; y++)
         {

        for(x = 0; x < tempTemplateWidth; x++)
          {

       float radian = (float)j * degree * CV_PI / 180.0f;
       int scale = y * tempTemplateWidth + x;

       int rotateY = - sin(radian) * ((float)x - (float)tempTemplateWidth / 2.0f) + cos(radian) * ((float)y - (float)tempTemplateHeight / 2.0f) + tempTemplateHeight / 2;

      int rotateX = cos(radian) * ((float)x - (float)tempTemplateWidth / 2.0f) + sin(radian) * ((float)y - (float)tempTemplateHeight / 2.0f) + tempTemplateWidth / 2;


      if(rotateY < tempTemplateHeight && rotateX < tempTemplateWidth && rotateY >= 0 && rotateX  >= 0)

      rotateBinaryTemplateImage->imageData[scale] = tempBinaryTemplateImage->imageData[rotateY * tempTemplateWidth + rotateX];

    }
   }

    //cvShowImage(windowNameSource, rotateBinaryTemplateImage);
    //cvWaitKey(0);

   cvMatchTemplate(binarySourceImage, rotateBinaryTemplateImage, result, CV_TM_SQDIFF_NORMED); 

   //cvMatchTemplate(binarySourceImage, rotateBinaryTemplateImage, result, CV_TM_SQDIFF);  

   cvMinMaxLoc(result, &minVal, NULL, &minLoc, NULL, NULL);
   printf(": %f%%\n", (int)(i * 0.5 * 100), j * 20, (1 - minVal) * 100);    

   if(minVal < 0.065) // 1 - 0.065 = 0.935 : 93.5% 
    {
      tempLoc.x = minLoc.x + tempTemplateWidth;
      tempLoc.y = minLoc.y + tempTemplateHeight;
     cvRectangle(destinationImage, minLoc, tempLoc, CV_RGB(0, 255, 0), 1, 8, 0);

    }
    }

    //cvShowImage(windowNameSource, result);
    //cvWaitKey(0);

    cvReleaseImage(&tempBinaryTemplateImage);
    cvReleaseImage(&result);

   }

   // cvShowImage(windowNameSource, sourceImage);
   // cvShowImage(windowNameCoefficientOfCorrelation, result); 

    cvShowImage(windowNameDestination, destinationImage);
    key = cvWaitKey(0);

    cvReleaseImage(&sourceImage);
    cvReleaseImage(&templateImage);
    cvReleaseImage(&graySourceImage);
    cvReleaseImage(&grayTemplateImage);
    cvReleaseImage(&binarySourceImage);
    cvReleaseImage(&binaryTemplateImage);
    cvReleaseImage(&destinationImage);

    cvDestroyWindow(windowNameSource);
    cvDestroyWindow(windowNameDestination);
    cvDestroyWindow(windowNameCoefficientOfCorrelation);

     }

结果:

模板图片:

结果图像:

上面的函数在此图像中的完美匹配(角度和比例不变)周围放置矩形......

The function above puts rectangles around the perfect matches (angle and scale invariant) in this image .....

现在,我一直在尝试将代码移植到 C++ 接口中.如果有人需要更多详细信息,请告诉我.

Now, I have been trying to port the code into C++ interface. If anyone needs more details please let me know.

推荐答案

以上代码的C++移植:

C++ Port of above code:

Mat TemplateMatch(Mat sourceImage, Mat templateImage){

    double minVal;
    Point minLoc;
    Point tempLoc;

    Mat graySourceImage = Mat(sourceImage.size(),CV_8UC1);
    Mat grayTemplateImage = Mat(templateImage.size(),CV_8UC1);
    Mat binarySourceImage = Mat(sourceImage.size(),CV_8UC1);
    Mat binaryTemplateImage = Mat(templateImage.size(),CV_8UC1);
    Mat destinationImage = Mat(sourceImage.size(),CV_8UC3);

    sourceImage.copyTo(destinationImage);

    cvtColor(sourceImage, graySourceImage, CV_BGR2GRAY);
    cvtColor(templateImage, grayTemplateImage, CV_BGR2GRAY);

    threshold(graySourceImage, binarySourceImage, 200, 255, CV_THRESH_OTSU );
    threshold(grayTemplateImage, binaryTemplateImage, 200, 255, CV_THRESH_OTSU);

    int templateHeight = templateImage.rows;
    int templateWidth = templateImage.cols;

    float templateScale = 0.5f;

    for(int i = 2; i <= 3; i++){

        int tempTemplateHeight = (int)(templateWidth * (i * templateScale));
        int tempTemplateWidth = (int)(templateHeight * (i * templateScale));

        Mat tempBinaryTemplateImage = Mat(Size(tempTemplateWidth,tempTemplateHeight),CV_8UC1);
        Mat result = Mat(Size(sourceImage.cols - tempTemplateWidth + 1,sourceImage.rows - tempTemplateHeight + 1),CV_32FC1);

        resize(binaryTemplateImage,tempBinaryTemplateImage,Size(tempBinaryTemplateImage.cols,tempBinaryTemplateImage.rows),0,0,INTER_LINEAR);

        float degree = 20.0f;

        for(int j = 0; j <= 9; j++){

            Mat rotateBinaryTemplateImage = Mat(Size(tempBinaryTemplateImage.cols, tempBinaryTemplateImage.rows), CV_8UC1);

            for(int y = 0; y < tempTemplateHeight; y++){
                for(int x = 0; x < tempTemplateWidth; x++){
                    rotateBinaryTemplateImage.data[y * tempTemplateWidth + x] = 255;
                }
            }


            for(int y = 0; y < tempTemplateHeight; y++){
                for(int x = 0; x < tempTemplateWidth; x++){

                    float radian = (float)j * degree * CV_PI / 180.0f;
                    int scale = y * tempTemplateWidth + x;

                    int rotateY = - sin(radian) * ((float)x - (float)tempTemplateWidth / 2.0f) + cos(radian) * ((float)y - (float)tempTemplateHeight / 2.0f) + tempTemplateHeight / 2;
                    int rotateX = cos(radian) * ((float)x - (float)tempTemplateWidth / 2.0f) + sin(radian) * ((float)y - (float)tempTemplateHeight / 2.0f) + tempTemplateWidth / 2;

                    if(rotateY < tempTemplateHeight && rotateX < tempTemplateWidth && rotateY >= 0 && rotateX  >= 0)
                        rotateBinaryTemplateImage.data[scale] = tempBinaryTemplateImage.data[rotateY * tempTemplateWidth + rotateX];
                }
            }

            matchTemplate(binarySourceImage, rotateBinaryTemplateImage, result, CV_TM_SQDIFF_NORMED);

            minMaxLoc(result, &minVal, 0, &minLoc, 0, Mat());

            cout<<(int)(i * 0.5 * 100)<<" , "<< j * 20<<" , "<< (1 - minVal) * 100<<endl;

            if(minVal < 0.065){ // 1 - 0.065 = 0.935 : 93.5%
                tempLoc.x = minLoc.x + tempTemplateWidth;
                tempLoc.y = minLoc.y + tempTemplateHeight;
                rectangle(destinationImage, minLoc, tempLoc, CV_RGB(0, 255, 0), 1, 8, 0);
            }
        }
    }
    return destinationImage;
}

这篇关于使用 OpenCV 进行角度和尺度不变模板匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆