使用OpenCV进行角度和比例不变模板匹配

时间:2013-07-24 07:30:55

标签: opencv template-matching

函数将模板图像从0旋转到180度(或高达360度),以搜索源图像中的所有相关匹配(在所有角度),即使是不同的比例。

该函数已在OpenCV C接口中编写。当我尝试将其移植到openCV C ++界面时,我遇到了很多错误。有人请帮我把它移植到OpenCV C ++界面。

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

     }

结果:

模板图片:

enter image description here

结果图片:

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

enter image description here

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

1 个答案:

答案 0 :(得分:3)

以上代码的C ++端口:

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