Bug or not bug? knnMatch from BruteForceMatcher_GPU
There is a problem of the match decriptors on the GPU.
OpenCV 2.4.5, CUDA 5.0
I tried to transfer my SURF matcher from the CPU to the GPU and got such a strange result. I use knnMatch and findHomography + perspectiveTransform together with my function, which checks the corners of the bounding box for the result to more precision.
GPU part:
const int baseImagesSize = baseImages.size();
SURF_GPU surf(1500);
surf.extended = false;
GpuMat keypoints_test_GPU, descriptors_test_GPU;
surf(frame, GpuMat(), keypoints_test_GPU, descriptors_test_GPU);
vector<float> descriptors_test_CPU;
surf.downloadDescriptors(descriptors_test_GPU, descriptors_test_CPU);
Mat descriptors_test_CPU_Mat(descriptors_test_CPU);
vector<Point2f> objs_corners(4);
BruteForceMatcher_GPU< L2<float> > matcher;
vector<KeyPoint> keypoints_test_CPU;
surf.downloadKeypoints(keypoints_test_GPU, keypoints_test_CPU);
for (int i = 0; i < baseImagesSize; ++i)
{
//Get the corners from the object
objs_corners[0] = cvPoint(0,0);
objs_corners[1] = cvPoint( baseImages[i].cols, 0 );
objs_corners[2] = cvPoint( baseImages[i].cols, baseImages[i].rows );
objs_corners[3] = cvPoint( 0, baseImages[i].rows );
//cout<<endl<<objs_corners[0]<<" "<<objs_corners[1]<<" "<<objs_corners[2]<<" "<<objs_corners[3]<<endl;
GpuMat keypoints_tmp_GPU, descriptors_tmp_GPU;
surf(baseImages[i], GpuMat(), keypoints_tmp_GPU, descriptors_tmp_GPU);
GpuMat trainIdx, distance;
vector< vector<DMatch> > matches;
matcher.knnMatch(descriptors_test_GPU, descriptors_tmp_GPU, matches, 2);
vector<KeyPoint> keypoints_tmp_CPU;
surf.downloadKeypoints(keypoints_tmp_GPU, keypoints_tmp_CPU);
std::vector<DMatch > good_matches;
for(int k = 0; k < min(descriptors_test_CPU_Mat.rows-1,(int) matches.size()); k++) //THIS LOOP IS SENSITIVE TO SEGFAULTS
{
if((matches[k][0].distance < 0.6*(matches[k][1].distance)) && ((int) matches[k].size()<=2 && (int) matches[k].size()>0))
{
good_matches.push_back(matches[k][0]);
}
}
vector<Point2f> obj;
vector<Point2f> scene;
vector<Point2f> scene_corners(4);
Mat H;
Mat img (baseImages[i]), img_matches, frame_cpu (frame);
std::ostringstream o_stream;
o_stream<<"Logo_save/"<<baseImagesNames[i];
try
{
drawMatches( img, keypoints_tmp_CPU, frame_cpu, keypoints_test_CPU, good_matches, img_matches, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
imwrite(o_stream.str(),img_matches);
}
catch(...)
{
cout<<"Error in drawMatches name: "<< baseImagesNames[i]<<endl;
}
if (good_matches.size() >= 4)
{
for( int k = 0; k < good_matches.size(); k++ )
{
//Get the keypoints from the good matches
obj.push_back( (keypoints_tmp_CPU)[ good_matches[k].queryIdx ].pt );
scene.push_back( keypoints_test_CPU[ good_matches[k].trainIdx ].pt );
}
cout<<good_matches.size()<<" "<<baseImagesNames[i]<<endl;
H = findHomography( obj, scene, CV_RANSAC);
perspectiveTransform( objs_corners, scene_corners, H);
bool falseDetect = isSmallAngle(scene_corners);
//cout<< falseDetect<< endl;
if(!falseDetect)
{
cout<<"DETECT "<<baseImagesNames[i]<<endl;
}
}
matcher.clear();
}
Bad result on GPU (MIN_HESSIAN==1500):
Bad result on GPU (MIN_HESSIAN==400):
CPU part:
SurfFeatureDetector detector( MIN_HESSIAN );//MIN_HESSIAN==400
const int baseImagesSize = baseImages.size();
vector< vector<KeyPoint> > kp_objects(baseImagesSize);
//Calculate descriptors (feature vectors)
SurfDescriptorExtractor extractor;
vector<Mat> des_objects(baseImagesSize);
FlannBasedMatcher matcher;
//namedWindow("SURF feature detector");
vector< vector<Point2f> > objs_corners(baseImagesSize,vector<Point2f>(4));
for (int i = 0; i < baseImagesSize; ++i)
{
detector.detect(baseImages[i], kp_objects[i]);
extractor.compute(baseImages[i], kp_objects[i], des_objects[i]);
//Get the corners from the object
(objs_corners[i])[0] = cvPoint(0,0);
(objs_corners[i])[1] = cvPoint( baseImages[i].cols, 0 );
(objs_corners[i])[2] = cvPoint( baseImages[i].cols, baseImages[i].rows );
(objs_corners[i])[3] = cvPoint( 0, baseImages[i].rows );
}
Mat des_image;
std::vector<KeyPoint> kp_image;
Mat image;
cvtColor(frame, image, CV_RGB2GRAY);
detector.detect( image, kp_image );
extractor.compute( image, kp_image, des_image );
for (int i = 0; i < baseImagesSize; ++i)
{
Mat img_matches;
std ...
Maybe there exist an option, which is differently set, like with the ORB descriptor: see e.g. http://answers.opencv.org/question/10835/orb_gpu-not-as-good-as-orbcpu/ . One note: could you please update this question with the content of the stackoverflow-question, so that it these posts are independent - thank you!
Hmm.. I'll try it. How can I download descriptors from ORB_GPU? In my code I used
surf.downloadDescriptors(descriptors_test_GPU, descriptors_test_CPU)
I just meant, that the bug may be similar to the one in the link, i.e. that maybe an option is not set in the GPU version but is set in the CPU. However, Vladislav already figured your concrete problem out ;) .