2
votes

I find that OpenCV's new class SURF does not act the same as SurfFeatureDetector. What's wrong with it?

Some example with two pictures:

..................................img_1..................................................................... img_2...................................

img_1img_2

use it like ./a.out ./img_1.png ./img_2.png

// STL
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
// C-Standard
#include <cstdio>
#include <ctime>
#include <cstdlib>
// OpenCV
#include <opencv2/opencv.hpp>
#include <opencv2/legacy/legacy.hpp>
#include <opencv2/nonfree/nonfree.hpp>

void print(const std::string & filename, const std::vector<std::vector<cv::DMatch>> & vec) {
    FILE *file = fopen(filename.c_str(), "w");
    fprintf(file, "{\n");
    for(auto & i : vec)
        fprintf(file, "    { {%d,%d,%f}, {,%d,%d,%f} },\n",
                i[0].queryIdx, i[0].trainIdx, i[0].distance,
                i[1].queryIdx, i[1].trainIdx, i[1].distance);
    fprintf(file, "}\n");
    fclose(file);
}

void test1(const std::string & imgf_1, const std::string & imgf_2) {
    cv::Mat img_1;
    cv::Mat img_2;
    std::vector<cv::KeyPoint> keypoints_1, keypoints_2;
    cv::Mat descriptors_1, descriptors_2;
    std::vector<std::vector<cv::DMatch>> matches;

    img_1 = cv::imread(imgf_1);
    img_2 = cv::imread(imgf_2);
    int minhessin = 400;
    cv::SurfFeatureDetector detector(minhessin);
    cv::SurfDescriptorExtractor extractor;
    cv::BFMatcher bfMatcher(cv::NORM_L2);

    keypoints_1.clear(); keypoints_2.clear();
    detector.detect(img_1, keypoints_1);
    extractor.compute(img_1, keypoints_1, descriptors_1);
    detector.detect(img_2, keypoints_2);
    extractor.compute(img_2, keypoints_2, descriptors_2);
    matches.clear();
    bfMatcher.knnMatch(descriptors_1, descriptors_2, matches, 2);

    print("main_bak.log", matches);
}

void test2(const std::string & imgf_1, const std::string & imgf_2) {
    cv::Mat img_1;
    cv::Mat img_2;
    std::vector<cv::KeyPoint> keypoints_1, keypoints_2;
    cv::Mat descriptors_1, descriptors_2;
    std::vector<std::vector<cv::DMatch>> matches;

    img_1 = cv::imread(imgf_1);
    img_2 = cv::imread(imgf_2);
    const double hessianThreshold = 400;
    cv::SURF detector2(hessianThreshold);
    cv::BFMatcher bfMatcher(cv::NORM_L2);

    keypoints_1.clear(); keypoints_2.clear();
    detector2(img_1, cv::Mat(), keypoints_1, descriptors_1);
    detector2(img_2, cv::Mat(), keypoints_2, descriptors_2);
    matches.clear();
    bfMatcher.knnMatch(descriptors_1, descriptors_2, matches, 2);

    print("main.log", matches);
}

int main(int argc, char * argv[])
{
    if(argc < 3) {
        std::cout << "usage: " << argv[0] << " img_1 img_2" << std::endl;
        return 1;
    }
    test1(argv[1], argv[2]);
    test2(argv[1], argv[2]);

    return 0;
}

The log's heading 5 lines are shown here:

main_bak.log:

{
    { {0,0,0.000787}, {,0,2,0.126846} },
    { {1,1,0.001695}, {,1,167,0.353709} },
    { {2,2,0.000860}, {,2,0,0.127105} },
    { {3,3,0.002939}, {,3,5,0.333215} },
    { {4,4,0.001360}, {,4,115,0.294008} },

main.log:

{
    { {0,0,0.000900}, {,0,2,0.143810} },
    { {1,1,0.024048}, {,1,107,0.621702} },
    { {2,2,0.003646}, {,2,0,0.144049} },
    { {3,3,0.032238}, {,3,5,0.604136} },
    { {4,4,0.001449}, {,4,87,0.591502} },
1
Not really a programming question... Maybe the way the algorithms parameter are handled ?kebs
I know it's not a programming question. However, the distance changing from '0.001695' to '0.024048' might due to some problems.Adam
In the function test1, declare extractor as cv::SurfDescriptorExtractor extractor(minHessian);sgarizvi
@sgarizvi Yeah, you got it right. Thx. Please answer it, so that I can mark you as the best answer.Adam

1 Answers

2
votes

The classes cv::SurfFeatureDetector and cv::SurfDescriptorExtractor are aliases of the class cv::SURF. The difference in results is due to the following reason:

In the function test1, detector and extractor objects are being initialized with different parameters. detector is using minHessian value of 400 while extractor is using the opencv implementation defined default value.

In function test2, keypoint detection and descriptor computation are done using a single cv::SURF object with hessianThreshold value of 400.

To reproduce the results of test2 in test1, initialize both objects with same parameters like this:

int minhessin = 400;
cv::SurfFeatureDetector detector(minhessin);
cv::SurfDescriptorExtractor extractor(minHessian);