0

I am trying to use OpenCV for generating descriptors at keypoints in an image on iOS. I have done feature detection using my own algorithm and now want to extract the descriptors at these points.

I implemented the following code to do this:

cv::Mat frame = LH_ImageProcessing::extractGrayFromBGRA(Img, 480, 640);
std::vector<cv::KeyPoint> keyPoints;
cv::Mat descriptors;

for (int i = 0; i < cornersDetected; i++) {
  keyPoints.push_back(cv::KeyPoint((float) cornerArray[i*2], (float) cornerArray[i*2+1], 5));
}

cv::BriefDescriptorExtractor extractor;
extractor.compute(frame, keyPoints, descriptors);

However the descriptors Mat is always empty after I run the "compute" function. All the pointers are just NULL, although I can clearly see that the keyPoints array is a reduced size after I run it. Which means that it is removing keypoints that it can't extract descriptors for.

I thought it was my implementation so I used a built in detector (SurfDetector) and copied the implementation from the OpenCV FREAK example. But I end up with the same result.

Is anyone else having issues, or have I missed something fundamental in OpenCV?

EDIT:

So I have further tracked down the issue. It appears that the pass by reference doesn't change the original cv::Mat data structure.

The function declaration for the compute function looks as follows:

void DescriptorExtractor::compute( const Mat& image, std::vector<KeyPoint>& keypoints, Mat& descriptors ) const 
{
....
computeImpl( image, keypoints, descriptors );
}

The computeImpl is the function that actually computes the descriptors. In my case the BRIEF descriptor.

void BriefDescriptorExtractor::computeImpl(const Mat& image, std::vector<KeyPoint>& keypoints, Mat& descriptors) const

When the computeImpl function returns the descriptors variable is what I would expect. It has been initialized and contains the data I want. However, when the DescriptorExtractor::compute method returns the new descriptors structure isn't passed back to my main code, even though it is a pass by reference method.

What could be causing this?

EDIT 2:

Here are a few screenshots of my watch variables during debug.

The descriptors Mat inside the .compute function just before the function returns The descriptors Mat inside the .compute function just before the function returns

Just after the .compute function returns into my calling function Just after the .compute function returns into my calling function

Chris Maes
  • 35,025
  • 12
  • 111
  • 136
System123
  • 523
  • 5
  • 14
  • Did you check the dscriptors immediately after .compute or id your code encapsulated in another function? – Micka Jun 02 '14 at 12:17
  • My code is shown at the top. I set a break point immediately after .compute and checked it there. The entire cv::Mat structure is just full of NULL pointers, like it is after I initially define it. – System123 Jun 02 '14 at 13:40
  • Leave a comment or criticism rather than just down voting. I don't think there is anything pointless about this question. – System123 Jun 02 '14 at 13:47
  • sorry, can't test on iOS... what do you mean by "all pointers are NULL"? which pointers? – Micka Jun 02 '14 at 14:11
  • See the 2 screen shots I added to the post. The 2nd one should look the same as the first one as it is pass by reference. – System123 Jun 03 '14 at 06:53
  • have you tried the opencv 2.4 branch instead of the (bleeding edge) 3.0 branch you're currently using ? (UMat in the sceenshot gives it away) – berak Jun 03 '14 at 07:06
  • Yes I was using 2.4.9 with the same issue. I compiled 3.0 to see if maybe it fixed the problem. – System123 Jun 03 '14 at 07:19

1 Answers1

1

So I finally figured this out. The trick is to use a pointer and initialize an empty cv::Mat and then pass this pointer to the compute function. OpenCV then reinitializes it in the .compute function and when everything returns the pointer is pointing to the new data structure.

It seems that the problem came from the compiler optimizing out the creation of an empty cv::Mat, thus when compute returned the memory memory was freed.

I changed:

cv::Mat descriptors;
...
ext.compute(frame, keyPoints, descriptors);

to

cv::Mat *descriptors = new cv::Mat;
...
ext.compute(frame, keyPoints, *descriptors);

and all works perfectly now.

System123
  • 523
  • 5
  • 14