Bug in cv::Orb? - opencv

I recently found some very strange behavior in opencv's ORB descriptor.
cv::Mat grey; //greyscale image
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
cv::ORB detector;
detector(grey,cv::Mat(),keypoints,descriptors);
The above code consistently crashes if given an image containing no potential keypoints (a black image for example) with the error
OpenCV Error: Assertion failed (m.dims >= 2) in Mat, file /Users/user/slave/ios_framework/src/opencv/modules/core/src/matrix.cpp, line 268
I found that to fix the problem I could do the following
cv::Mat grey;
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
cv::ORB detector;
detector(grey,cv::Mat(),keypoints);
if(keypoints.size() > 0)
{
detector(grey,cv::Mat(),keypoints,descriptors,true);
}
Which first detects keypoints and then generates their descriptors if any keypoints were detected. I am using opencv2 as a .framework on iOS.
Is this a bug in OpenCV? If not, what am I doing wrong? If so, are there any versions in which it is fixed?

I just ran this code
cv::Mat grey = cv::Mat::zeros(100, 100, CV_8UC1);
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
cv::ORB detector;
detector(grey,cv::Mat(),keypoints,descriptors);
with OpenCV 2.4.1 without problems.
Did you debug into your code to see where exactly the assertion fails?

Related

Example code for SIFT in OpenCV 3?

Im new to OpenCV, Im trying to use SIFT to extract key points from a grayscale image. But failing to successfully compile the code. There seems to be no clear help on the internet for usage of SIFT. Pls help. Thanks.
while(true)
{
Mat myFrame;
Mat grayFrame;
capture.read(myFrame);
cvtColor(myFrame, grayFrame, CV_BGR2GRAY);
vector<Vec2f> outputArray;
vector<KeyPoint> keypoint;
Feature2D EXTRACTOR;
Mat descriptors;
EXTRACTOR.detectAndCompute(grayFrame, outputArray, keypoint, descriptors);
}
vector<KeyPoint> keyVector;
Mat outputDiscriptor;
Ptr<SIFT> detector = SIFT::create();
detector->detect(grayFrame, keyVector);
//here grayFrame is the gray scale of the original frame/image
if you want to get the descriptors of the key points use the
detector->compute(grayFrame, keyVector)

Opencv Unhandled exception in contour.exe

My code in OpenCV works well up until when I want to find contours:
findContours(src, contours,hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
then I keep getting the following error:
"Unhandled exception at 0x773e3e28 in Contour.exe: Microsoft C++
exception: cv::Exception at memory location 0x002ff3ac.."
Do you have any idea about this error?
My full code is below.
Thanks
Mat src=Mat(100,200,CV_64F),newimg;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
for (int i=25;i<80;i++)
for(int j=25;j<80;j++)
src.at<double>(i,j)=1;
imshow("img",src);
waitKey(0);
findContours(src, contours,hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
Quoting from OpenCV documentation about findContours
image – Source, an 8-bit single-channel image. Non-zero pixels are treated as 1’s. Zero pixels remain 0’s, so the image is treated as binary . You can use compare() , inRange() , threshold() , adaptiveThreshold() , Canny() , and others to create a binary image out of a grayscale or color one. The function modifies the image while extracting the contours. If mode equals to CV_RETR_CCOMP or CV_RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1).
You can adjust your code converting your CV_64FC1 image to a CV_8UC1 like:
...
Mat1b img8u;
src.convertTo(img8u, CV_8U);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(img8u, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
...
In addition, from the comments turns out that you are using Visual Studio 2010, but linking OpenCV built with msvc11 (Visual Studio 2012).
You need either to use Visual Studio 2012, or recompile OpenCV with msvc10 (Visual Studio 2010). If you decide to upgrade VS, you can go directly to VS2013 (and link to vc12), or to VS2015 (but you need to recompile OpenCV as well).
Your problem is you are giving "findContours" a CV_64F image when it requires a CV_8UC1 image. You generally pass findContours the output of an edge detector. (E.G. Canny).
If you modify your code to the following you can find the contours in an image after filtering it through Canny.
Mat src=Mat(100,200,CV_64F),newimg;
Mat tCannyMat;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
for (int i=25;i<80;i++)
for(int j=25;j<80;j++)
src.at<double>(i,j)=1;
imshow("img",src);
waitKey(0);
int lowThreshold = 0x3f;//This is the single value threshold
int ratio = 3;//This is the ratio to apply for the entire pixel
int kernel_size = 3;//This is the canny kernel size
//You can use your own edge detector/a different one here if you wish.
//Canny merely serves to give a working example.
cv::Canny( src, tCannyMat, lowThreshold, lowThreshold*ratio, kernel_size );
findContours(tCannyMat, contours,hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);

doubts regarding the output of canny and findcountours in OpenCV

I am using the standard flow to process an image and just find I cannot understand the meaning of contours generated by canny and findCountours.
Here is the image:
And after canny:
after findContours, it has 4 contours. So I draw the 4 contours out.
That is the confusing part: why does it have 4 contours instead of 2? Because from the canny output, we can only see 2 contours: the outside one and the inside one.
Could someone clear my doubts?
Thanks
Deryk
code is here:
Mat src = imread("images/andgate.png");
Mat gray;
cvtColor(src, gray, CV_BGR2GRAY);
Mat bw;
Canny(gray, bw, 100, 200);
vector<vector<Point> > contours2;
vector<Vec4i> hierarchy2;
findContours(bw, contours2, hierarchy2,CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);

OpenCV findContours destroying source image

I writing a code that draw circle, line and rectangle in a single channel blank image. After that I just find out the contour in the image and I am getting all the contour correctly. But after finding the contour my source image is getting distorted. Why this happening ? Any one can help me to solve it out. And my code look like below.
using namespace cv;
using namespace std;
int main()
{
Mat dst = Mat::zeros(480, 480, CV_8UC1);
Mat draw= Mat::zeros(480, 480, CV_8UC1);
line(draw, Point(100,100), Point(150,150), Scalar(255,0,0),1,8,0);
rectangle(draw, Rect(200,300,10,15), Scalar(255,0,0),1, 8,0);
circle(draw, Point(80,80),20, Scalar(255,0,0),1,8,0);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( draw, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
for( int i = 0; i< contours.size(); i++ )
{
Scalar color( 255,255,255);
drawContours( dst, contours, i, color, 1, 8, hierarchy );
}
imshow( "Components", dst );
imshow( "draw", draw );
waitKey(0);
}
Source image
Distorted source after finding contour
Documentation clearly states that source image is altered when using findContours.
http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=findcontours#findcontours
See first note.
If you need the source image, you have to run findContours on copy.
try using
findContours( draw.clone(), contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
For me, the second image looks like what I would expect as a result from an edge detection algorithm. My guess is the findContours function overwrites the original image with the result found.
Have a look here.
I think that the problem is that you are expecting a perfect plot from the findContours and it gives you an ugly drawing.
FindContours is not gonna give an exact plot of your figures. You must use the drawContours in order to generate a properly image.
Look the reference here: http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=findcontours#findcontours
You can see that the first parameter is Input/Output array. So the function uses the same array to open, modify and saving the image. That's why you are getting a distorted image.
In addition see the parameters explanation. When it talks about the first parameter it says: "The function modifies the image while extracting the contours."
I havn't worked a lot with findContours but i never had a clear image of what I wanted. I must use always the drawContours to get a nice plot of it.
Otherwise you can use the Canny function wich is gonna give you the edges instead of the contours.

findContours error 'support only 8uC1 images'

Trying to run findContours on a binary image"
Mat conv(image.size(), CV_8U);
image.convertTo(conv, CV_8U);
vector<vector<cv::Point> > contours;
findContours(conv, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
thorws error:
OpenCV Error: Unsupported format or combination of formats ([Start]FindContours support only 8uC1 images) in cvStartFindContours,
Any ideas?
Thanks
From the documentation:
C++: void Mat::convertTo(OutputArray m, int rtype, double alpha=1, double beta=0 ) const
Parameters:
rtype – desired output matrix type or, rather, the depth since the number of
channels are the same as the input has; if rtype is negative, the output matrix will have the same type as the input.
You see that the number of channels is not changed by convertTo, this means most probably that you get 3 channels (r, g and b). However findContours requires a monochrome image.
You need to convert the image to black-and-white:
cv::Mat bwImage;
cv::cvtColor(image, bwImage, CV_RGB2GRAY);
vector< vector<cv::Point> > contours;
cv::findContours(bwImage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

Resources