Hi!
I am currently trying to use opencv's FLANN Based Matcher using SURF detectors to try match a template in a scene. However the template is showing the image from a different rotation, scale and perspective. So far the code has been successful at finding some matches but not enough for a bounding box to be drawn around the template in the scene (Using findHomography() and perspectiveTransform()).
The objects of interest are birds in flight and as such are ever changing. What I want to achieve is to have a bounding box drawn around the object of interest in the scene when as little as 2 "good matches" are found.
Any and all help would be greatly appreciated!
Thanks,
Levi.
The code for this matching function is included below:
Mat Homography(Mat tmpl, Mat scene)
{
cvtColor(scene,scene,COLOR_BGR2GRAY);
cvtColor(tmpl,tmpl,COLOR_BGR2GRAY);
Mat img_matches;
//Detect the keypoints and extract descriptors (feature vectors) using SURF
int minHessian = 400;
Ptr<SURF> detector = SURF::create( minHessian );
vector<KeyPoint> keypoints_tmpl, keypoints_scene;
Mat descriptors_tmpl, descriptors_scene;
detector->detectAndCompute(tmpl, Mat(), keypoints_tmpl, descriptors_tmpl );
detector->detectAndCompute(scene, Mat(), keypoints_scene, descriptors_scene );
//Matching descriptor vectors using FLANN matcher
if ( descriptors_tmpl.empty() )
{
//cvError(0,"MatchFinder","1st descriptor empty",__FILE__,__LINE__);
return frame;
}
if ( descriptors_scene.empty() )
{
//cvError(0,"MatchFinder","2nd descriptor empty",__FILE__,__LINE__);
return frame;
}
FlannBasedMatcher matcher;
vector< DMatch > matches;
matcher.match( descriptors_tmpl, descriptors_scene, matches );
double max_dist = 0; double min_dist = 100;
//max and min distances between keypoints
for( int i = 0; i < descriptors_tmpl.rows; i++ )
{
double dist = matches[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
//Finds "good" matches (distance less than 3*min_dist )
vector< DMatch > good_matches;
for( int i = 0; i < descriptors_tmpl.rows; i++ )
{
if( matches[i].distance < 3*min_dist )
{
good_matches.push_back( matches[i]);
}
}
drawMatches( tmpl, keypoints_tmpl, scene, keypoints_scene,
good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
//Localize the tmpl
vector<Point2f> templ;
vector<Point2f> scn;
for( int i = 0; i < good_matches.size(); i++ )
{
//keypoints from the good matches
templ.push_back( keypoints_tmpl[ good_matches[i].queryIdx ].pt );
scn.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
}
Mat H = findHomography( templ, scn, RANSAC );
//corners from the template ( the object to be "detected" )
vector<Point2f> tmpl_corners(4);
tmpl_corners[0] = cvPoint(0,0);
tmpl_corners[1] = cvPoint( tmpl.cols, 0 );
tmpl_corners[2] = cvPoint( tmpl.cols, tmpl.rows );
tmpl_corners[3] = cvPoint( 0, tmpl.rows );
vector<Point2f> scene_corners(4);
if(!H.empty())
{
perspectiveTransform( tmpl_corners, scene_corners, H);
}
//-- Draw lines between the corners (bounding box)
line( img_matches, scene_corners[0] + Point2f( tmpl.cols, 0), scene_corners[1] + Point2f( tmpl.cols, 0), Scalar(0, 255, 0), 4 );
line( img_matches, scene_corners[1] + Point2f( tmpl.cols, 0), scene_corners[2] + Point2f( tmpl.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[2] + Point2f( tmpl.cols, 0), scene_corners[3] + Point2f( tmpl.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[3] + Point2f( tmpl.cols, 0), scene_corners[0] + Point2f( tmpl.cols, 0), Scalar( 0, 255, 0), 4 );
return img_matches;
}
}