Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Features2D + Homography to find a known object on GPU/OpenCL

Hello, I slightly modified this tutorial : link text to use GPU with OpenCL. I just changed Mat to UMat, and also I used FAST as a detector and ORB descriptors, and BFMatcher instead of FlannBasedMatcher.

The modified code is as followed:

#include <stdio.h>
#include <iostream>
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/xfeatures2d.hpp"

#include <opencv2/core/ocl.hpp>

using namespace cv;
using namespace cv::xfeatures2d;
void readme();
/* @function main */
int main( int argc, char** argv )
{
  if( argc != 3 )
  { readme(); return -1; }
  UMat img_object = imread( argv[1], IMREAD_GRAYSCALE ).getUMat(ACCESS_READ);
  UMat img_scene = imread( argv[2], IMREAD_GRAYSCALE ).getUMat(ACCESS_READ);

  Ptr<FastFeatureDetector> detector = FastFeatureDetector::create(5,false,FastFeatureDetector::TYPE_9_16);
  Ptr<ORB> descriptor = ORB::create(500, 1.2f, 8, 1, 0, 2, cv::ORB::HARRIS_SCORE, 15);

  std::vector<KeyPoint> keypoints_object, keypoints_scene;
  UMat descriptors_object, descriptors_scene;

  detector->detect(img_object, keypoints_object);
  descriptor->compute(img_object, keypoints_object, descriptors_object);

  detector->detect(img_scene, keypoints_scene);

  descriptor->compute(img_scene, keypoints_scene, descriptors_scene);

  //-- Step 2: Matching descriptor vectors
  BFMatcher matcher(NORM_HAMMING);
  std::vector< DMatch > matches;
  matcher.match( descriptors_object, descriptors_scene, matches );
  double max_dist = 0; double min_dist = 100;
  //-- Quick calculation of max and min distances between keypoints
  for( int i = 0; i < descriptors_object.rows; i++ )
  { double dist = matches[i].distance;
    if( dist < min_dist ) min_dist = dist;
    if( dist > max_dist ) max_dist = dist;
  }
  printf("-- Max dist : %f \n", max_dist );
  printf("-- Min dist : %f \n", min_dist );
  //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
  std::vector< DMatch > good_matches;
  for( int i = 0; i < descriptors_object.rows; i++ )
  { if( matches[i].distance <= 3*min_dist )
     { good_matches.push_back( matches[i]); }
  }
  UMat img_matches;
  drawMatches( img_object, keypoints_object, img_scene, keypoints_scene,
               good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
               std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
  //-- Localize the object
  std::vector<Point2f> obj;
  std::vector<Point2f> scene;
  for( size_t i = 0; i < good_matches.size(); i++ )
  {
    //-- Get the keypoints from the good matches
    obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
    scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
  }
  Mat H = findHomography( obj, scene, RANSAC );
  //-- Get the corners from the image_1 ( the object to be "detected" )
  std::vector<Point2f> obj_corners(4);
  obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( img_object.cols, 0 );
  obj_corners[2] = cvPoint( img_object.cols, img_object.rows ); obj_corners[3] = cvPoint( 0, img_object.rows );
  std::vector<Point2f> scene_corners(4);
  perspectiveTransform( obj_corners, scene_corners, H);
  //-- Draw lines between the corners (the mapped object in the scene - image_2 )
  line( img_matches, scene_corners[0] + Point2f( img_object.cols, 0), scene_corners[1] + Point2f( img_object.cols, 0), Scalar(0, 255, 0), 4 );
  line( img_matches, scene_corners[1] + Point2f( img_object.cols, 0), scene_corners[2] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
  line( img_matches, scene_corners[2] + Point2f( img_object.cols, 0), scene_corners[3] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
  line( img_matches, scene_corners[3] + Point2f( img_object.cols, 0), scene_corners[0] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
  //-- Show detected matches
  cv::namedWindow("Good Matches & Object detection",CV_WINDOW_NORMAL);
  cv::resizeWindow("Good Matches & Object detection", 1300, 970);
  imshow( "Good Matches & Object detection", img_matches );
  waitKey(0);
  return 0;
  }
  /* @function readme */
  void readme()
  { std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << std::endl; }

OpenCL is initialized automatically, and my Geforce 1080Ti detected and used.

The problem is that it gives wrong results like this:

image description

If I make the same code with Mat instead of UMat, everything works fine, inliers are good and the object is detected.

So is there something wrong with my code that should be modified to run on GPU ? or is it something else.

I am using OpenCV 3.4.0 built from sources.

I tried building OpenCV with Cuda Toolkit 8.0 with included driver, same error. I tried newer Cuda Toolkit 9.1 with included driver (and according CMake options modifications), same error.

Is the FAST or ORB code for GPU running fine ?

Looking forward to your help... maybe try this code at home and tell me how it works for you.