Search code examples
c++opencv

BRIEF implementation with OpenCV 2.4.10


Does someone know of the link to BRIEF implementation with OpenCV 2.4? Regards.

PS: I know such questions are generally not welcome on SO, as the primary focus is what work you have done. But there was a similar question which was quite well received.

One of the answers to that questions suggests a generic manner for SIFT, which could be extended to BRIEF. Here is my slightly modified code.

#include <opencv2/nonfree/nonfree.hpp> 
#include <opencv2/highgui/highgui.hpp>

//using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{        
  Mat image = imread("load02.jpg", CV_LOAD_IMAGE_GRAYSCALE);
  cv::initModule_nonfree();
  // Create smart pointer for SIFT feature detector.
  Ptr<FeatureDetector> featureDetector = FeatureDetector::create("HARRIS"); // "BRIEF was initially written. Changed after answer."
  vector<KeyPoint> keypoints;

  // Detect the keypoints
  featureDetector->detect(image, keypoints); // NOTE: featureDetector is a pointer hence the '->'.

  //Similarly, we create a smart pointer to the SIFT extractor.
  Ptr<DescriptorExtractor> featureExtractor = DescriptorExtractor::create("BRIEF");

  // Compute the 128 dimension SIFT descriptor at each keypoint.
  // Each row in "descriptors" correspond to the SIFT descriptor for each keypoint
  Mat descriptors;
  featureExtractor->compute(image, keypoints, descriptors);

  // If you would like to draw the detected keypoint just to check
  Mat outputImage;
  Scalar keypointColor = Scalar(255, 0, 0);     // Blue keypoints.
  drawKeypoints(image, keypoints, outputImage, keypointColor, DrawMatchesFlags::DEFAULT);

  namedWindow("Output");
  imshow("Output", outputImage);

  char c = ' ';
  while ((c = waitKey(0)) != 'q');  // Keep window there until user presses 'q' to quit.

  return 0;

}

The issue with this code is that it gives an error: First-chance exception at 0x00007FFB84698B9C in Project2.exe: Microsoft C++ exception: cv::Exception at memory location 0x00000071F4FBF8E0.

The error results in the function execution breaking. A tag says that execution will resume at the namedWindow("Output"); line.

Could someone please help fix this issue, or suggest a new code altogether? Thanks.

EDIT: The terminal now shows an error: Assertion failed (!outImage.empty()) in cv::drawKeypoints, file ..\..\..\..opencv\modules\features2d\src\draw.cpp, line 115. The next statement from where the code will resume remains the same, as drawKepoints is called just before it.


Solution

  • In OpenCV, BRIEF is a DescriptorExtractor, not a FeatureDetector. According to FeatureDetector::create, this factory method does not support "BRIEF" algorithm. In other words, FeatureDetector::create("BRIEF") returns a null pointer and your program crashes.

    The general steps in feature matching are:

    1. Find some interesting (feature) points in an image: FeatureDetector
    2. Find a way to describe those points: DescriptorExtractor
    3. Try to match descriptors (feature vectors) in two images: DescriptorMatcher

    BRIEF is an algorithm only for step 2. You can use some other methods, HARRIS, ORB, ..., in step 1 and pass the result to step 2 using BRIEF. Besides, SIFT can be used in both step 1 and 2 because the algorithm provides methods for both steps.


    Here's a simple example to use BRIEF in OpenCV. First step, find points that looks interesting (key points) in an image:

    vector<KeyPoint> DetectKeyPoints(const Mat &image) 
    {
        auto featureDetector = FeatureDetector::create("HARRIS");
        vector<KeyPoint> keyPoints;
        featureDetector->detect(image, keyPoints);
        return keyPoints;
    }
    

    You can try any FeatureDetector algorithm instead of "HARRIS". Next step, compute the descriptors from key points:

    Mat ComputeDescriptors(const Mat &image, vector<KeyPoint> &keyPoints)
    {
        auto featureExtractor = DescriptorExtractor::create("BRIEF");
        Mat descriptors;
        featureExtractor->compute(image, keyPoints, descriptors);
        return descriptors;
    }
    

    You can use algorithm different than "BRIEF", too. And you can see that the algorithms in DescriptorExtractor is not the same as the algorithms in FeatureDetector. The last step, match two descriptors:

    vector<DMatch> MatchTwoImage(const Mat &descriptor1, const Mat &descriptor2)
    {
        auto matcher = DescriptorMatcher::create("BruteForce");
        vector<DMatch> matches;
        matcher->match(descriptor1, descriptor2, matches);
        return matches;
    }
    

    Similarly, you can try different matching algorithm other than "BruteForce". Finally back to main program, you can build the application from those functions:

    auto img1 = cv::imread("image1.jpg");
    auto img2 = cv::imread("image2.jpg");
    
    auto keyPoints1 = DetectKeyPoints(img1);
    auto keyPoints2 = DetectKeyPoints(img2);
    
    auto descriptor1 = ComputeDescriptors(img1, keyPoints1);
    auto descriptor2 = ComputeDescriptors(img2, keyPoints2);
    
    auto matches = MatchTwoImage(descriptor1, descriptor2);
    

    and use matches vector to complete your application. If you want to check the results, OpenCV also provides functions to draw results of step 1 & 3 in an image. For example, draw the matches in the final step:

    Mat result;
    drawMatches(img1, keyPoints1, img2, keyPoints2, matches, result);
    imshow("result", result);
    waitKey(0);