2

I have a program that takes for input a picture, and who's objective is to determine if a certain object (essentially an image) is contained with this picture. If so it tries to estimate it's position. This works really well when the object is in the picture. However I get a lot of false positives when I put anything complex enough in the picture.

I was wondering if there is any good way to filter out these false positives. Hopefully something not too computationally expensive.

My program is based on the tutorial found here. Except I use BRISK instead of SURF so I don't need the contrib stuff.

HOW I GET MATCHES

descriptorMatcher->match(descImg1, descImg2, matches, Mat());

GOOD MATCHES

double max_dist = 0; double min_dist = 100;

//-- Quick calculation of max and min distances between keypoints
for( int i = 0; i < descImg1.rows; i++ )
{ double dist = matches[i].distance;
  if( dist < min_dist ) min_dist = dist;
  if( dist > max_dist ) max_dist = dist;
}

std::vector< DMatch > good_matches;

for( int i = 0; i < descImg1.rows; i++ )
{ if( matches[i].distance < 4*min_dist )
 { good_matches.push_back( matches[i]); }
}

HOMOGRAPHY

std::vector<Point2f> obj;
std::vector<Point2f> scene;

for( int i = 0; i < good_matches.size(); i++ )
{
  //-- Get the keypoints from the good matches
  obj.push_back( keyImg1[ good_matches[i].queryIdx ].pt );
  scene.push_back( keyImg2[ good_matches[i].trainIdx ].pt );
}

Mat H = findHomography( obj, scene, FM_RANSAC );

OBJECT CORNERS

std::vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( img1.cols, 0 );
obj_corners[2] = cvPoint( img1.cols, img1.rows ); obj_corners[3] = cvPoint( 0, img1.rows );
std::vector<Point2f> scene_corners(4);

perspectiveTransform( obj_corners, scene_corners, H);
Anters Bear
  • 1,816
  • 1
  • 15
  • 41

1 Answers1

2

You cannot completely eliminate false positives. That's why RANSCAC algorithm is used to find homography. However, you may check if estimated homography is "good". See this question for details. And if estimated homography is wrong you may discard it and assume that no object is found. As you need at least 4 corresponding points to estimate homography, you can reject those homographies that were estimated using less points that a predefined threshold (eg.6). That will likely filter out all wrongly estimated homographies:

int minInliers = 6; //can be any value > 4
double reprojectionError = 3; // default value, you can change it to some lower to get more reliable estimation.
Mat mask;    
Mat H = findHomography( obj, scene, FM_RANSAC, reprojectionError, mask );
int inliers = 0;
for (int i=0; i< mask.rows; ++i)
{
    if(mask[i] == 1) inliers++;
}
if(inliers > minInliers)
{
    //homography is good
}

You can also test the method proposed in original SIFT paper to get better matches. You need to find two closest descriptors to each query point and then check if ratio between their distances is less that threshold (David Lowe suggest 0.8) Check this link for details:

descriptorMatcher->knnMatch( descImg1, descImg2, knn_matches, 2 );
//-- Filter matches using the Lowe's ratio test
const float ratio_thresh = 0.8f;
std::vector<DMatch> good_matches;
for (size_t i = 0; i < knn_matches.size(); i++)
{
    if (knn_matches[i][0].distance < ratio_thresh * knn_matches[i][1].distance)
    {
        good_matches.push_back(knn_matches[i][0]);
    }
}
Piotr Siekański
  • 1,665
  • 8
  • 14
  • hey thanks for the suggestions! you sure that's the right way to check inliners? It's always coming up with the same number as my matches :( – Anters Bear Jul 17 '19 at 17:02
  • 1
    you actually have to look at `mask[i] == 1` to check if a point at index `i` in `matches` or `scene` is an inliner. `mask` will actually always have the same number of rows as `scene`... – Anters Bear Jul 17 '19 at 17:37
  • Thanks @AntersBear for spotting this. The answer was corrected. – Piotr Siekański Jul 17 '19 at 18:50