Ask Your Question

Revision history [back]

Bug or not bug? knnMatch from BruteForceMatcher_GPU

There is a problem of the match decriptors on the GPU. I'm sorry, but the description in its entirety I posted on stackoverflow

Bug or not bug? knnMatch from BruteForceMatcher_GPU

There is a problem of the match decriptors on the GPU. I'm sorry, but the description in its entirety I posted on stackoverflow

Bug or not bug? knnMatch from BruteForceMatcher_GPU

There is a problem of the match decriptors on the GPU. I'm sorry, but the description

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 its entirety I posted 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 stackoverflowGPU (MIN_HESSIAN==1500): surf(1500)

Bad result on GPU (MIN_HESSIAN==400): surf(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::vector<vector<DMatch > > matches;
    std::vector<DMatch > good_matches;
    std::vector<Point2f> obj;
    std::vector<Point2f> scene;
    std::vector<Point2f> scene_corners(4);
    Mat H;
    matcher.knnMatch(des_objects[i], des_image, matches, 2);

    for(int k = 0; k < min(des_image.rows-1,(int) matches.size()); k++) //THIS LOOP IS SENSITIVE TO SEGFAULTS
    {
        if((matches[k][0].distance < 0.6*(matches[k][4].distance)) && ((int) matches[k].size()<=2 && (int) matches[k].size()>0))
        {
            good_matches.push_back(matches[k][0]);
        }
    }

    //Draw only "good" matches
    std::ostringstream o_stream;
    o_stream<<"Logo_save/"<<baseImagesNames[i];
    try
    {
        drawMatches( baseImages[i], kp_objects[i], image, kp_image, 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( (kp_objects[i])[ good_matches[k].queryIdx ].pt );
            scene.push_back( kp_image[ good_matches[k].trainIdx ].pt );
        }

        H = findHomography( obj, scene, CV_RANSAC);
        perspectiveTransform( objs_corners[i], scene_corners, H);
        bool falseDetect = isSmallAngle(scene_corners);
        if(!falseDetect)
        {
            cout<<"DETECT "<<baseImagesNames[i]<<endl;
        }


    }
}

Good result on CPU (MIN_HESSIAN==400): good result on CPU:

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): surf(1500)

Bad result on GPU (MIN_HESSIAN==400): surf(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::vector<vector<DMatch > > matches;
    std::vector<DMatch > good_matches;
    std::vector<Point2f> obj;
    std::vector<Point2f> scene;
    std::vector<Point2f> scene_corners(4);
    Mat H;
    matcher.knnMatch(des_objects[i], des_image, matches, 2);

    for(int k = 0; k < min(des_image.rows-1,(int) matches.size()); k++) //THIS LOOP IS SENSITIVE TO SEGFAULTS
    {
        if((matches[k][0].distance < 0.6*(matches[k][4].distance)) && ((int) matches[k].size()<=2 && (int) matches[k].size()>0))
        {
            good_matches.push_back(matches[k][0]);
        }
    }

    //Draw only "good" matches
    std::ostringstream o_stream;
    o_stream<<"Logo_save/"<<baseImagesNames[i];
    try
    {
        drawMatches( baseImages[i], kp_objects[i], image, kp_image, 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( (kp_objects[i])[ good_matches[k].queryIdx ].pt );
            scene.push_back( kp_image[ good_matches[k].trainIdx ].pt );
        }

        H = findHomography( obj, scene, CV_RANSAC);
        perspectiveTransform( objs_corners[i], scene_corners, H);
        bool falseDetect = isSmallAngle(scene_corners);
        if(!falseDetect)
        {
            cout<<"DETECT "<<baseImagesNames[i]<<endl;
        }


    }
}

Good result on CPU (MIN_HESSIAN==400): good result on CPU:

UPD (My function for check angle of border):

bool isSmallAngle(const std::vector<Point2f> scene_corners)

    {
        const float minAngle=70;
        const float maxAngle=120;
        const float minHW = 15;

        float height = abs(scene_corners[3].y-scene_corners[0].y);
        float width = abs(scene_corners[1].x-scene_corners[0].x);
        cout<< height<< " " << width << endl;
        if(height>minHW||width>minHW)
        {
            float left_top = innerAngle(scene_corners[1].x,scene_corners[1].y,scene_corners[3].x,scene_corners[3].y,scene_corners[0].x,scene_corners[0].y);
            float left_bot = innerAngle(scene_corners[0].x,scene_corners[0].y,scene_corners[2].x,scene_corners[2].y,scene_corners[3].x,scene_corners[3].y);
            float right_top = innerAngle(scene_corners[0].x,scene_corners[0].y,scene_corners[2].x,scene_corners[2].y,scene_corners[1].x,scene_corners[1].y);
            float right_bot = innerAngle(scene_corners[1].x,scene_corners[1].y,scene_corners[3].x,scene_corners[3].y,scene_corners[2].x,scene_corners[2].y);
            std::cout << left_top << " " << right_top << " " << right_bot << " " << left_bot << std::endl;
            return left_bot<minAngle||left_top<minAngle||right_top<minAngle||right_bot<minAngle||left_bot>maxAngle||left_top>maxAngle||right_top>maxAngle||right_bot>maxAngle;
        }
        else
        {
            return true;
        }
    }

    float innerAngle(float px1, float py1, float px2, float py2, float cx1, float cy1)
    {

        float angle;

        float ax = cx1-px1;
        float ay = cy1-py1;
        float bx = cx1-px2;
        float by = cy1-py2;
        float cost = (ax*bx+ay*by)/sqrt((ax*ax+ay*ay)*(bx*bx+by*by));
        if (cost!=0)
        {
            angle = acos(cost)*180/CV_PI;
        }
        else 
        {
            angle = 90;
        }
        return angle;
    }