findContours error 'support only 8uC1 images' - image-processing

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);

Related

findcontour function giving me incorrect number of contours

I am trying to get contours for an image using OpenCV4 and C++. I have defined the contours as vector of vector of points. When I use the function it is only giving me one set of contours.
vector<vector<cv::Point> > contours;
vector<cv::Vec4i> hierarchy;
findContours(border_image, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
cout<<"Size of contours -->"<< contours.size()<<endl;
border_image is a cv::Mat and has each pixel as CV_8UC1
Above code is returning size(length of vector of vector of points) as 1.
If I do the same in Python, I am getting the required number of contours. What am I doing wrong?
Python Version:
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
Above returns contours of length 112
Expected contours(Vector of Vector of Points) of length 112. I only got contours of length 1 which is nothing but first element(Vector of Points) in result obtained by Python.
What am I doing wrong? Someone help me out.

OpenCV: findContours seems to be tricked by combination of large filled areas and lines

I want to process the output from external image segmentation algorithm (the left frame), which consists of the large color-filled areas and contour lines between them. The grayscale image that is used to find contours seems Ok (right frame), so I don't think that Canny thresholds are the issue. However, when I try to find contours on this image (frame in the middle) I get this result. How can I detect the big areas properly?
int thresh = 100;
// segmenting received image by external algorithm
Felzenszwalb_segment(seg,src2_bgr,k,0.5,500);
// finding contours on the segmented image
Mat src_gray;
cvtColor( src2_bgr, src_gray, CV_BGR2GRAY );
imshow("gray", src_gray);
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using canny
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
/// Find contours
findContours( canny_output,
contours,
hierarchy,
CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
If it's needed, here is the segmentation algorithm I'm using, the file to include is segment.cpp, usage is shown in the commented out main() function.

How to judge color space of processed image?

I am studying the OpenCV. Now I am vary confusing the following problem.
Here is the code:
Mat img = imread("...");
Mat imgHSV;
Mat imgThresholded;
cvtColor(img, imgHSV, COLOR_BGR2HSV);
inRange(imgHSV, Scalar(150, 50, 75), Scalar(179, 255, 255), imgThresholded);
Now, I get a processed image imgThresholded. is this imgThresolded in RGB color space or HSV color space?
As per the documentation,
void inRange(InputArray src, InputArray lowerb, InputArray upperb,
OutputArray dst)
dst – output array of the same size as src and CV_8U type
This means that for 3 channel input image the output would be a single channel image, in case of thresholding, the output is a binary image which has only white(255) and black(0) pixels and the format is CV_8U only.
It is 1 a one channel image with either 0 or 255 values.
If you want to go back to your original RGB space just do the following:
cv::Mat FinalRGB;
cv::cvtColor(imgThresholded, imgThresholded, CV_GRAY2BGR);
cv::bitwise_and(imgThresholded, img, FinalRGB);
EDIT:
As #Micka stated:
cv::Mat imgMasked;
img.copyTo(imgMasked, imgThresholded);
will do the same idea but faster.
inRange() will give binary image. Not HSV or RGB. But yeah, it will consider HSV image for computation as you have given imHSV as the input image.
The function inRange() works as follows:
imThresholded (I) is set to 255 (all 1 -bits) if imHSV (I) is
within the specified 1D, 2D, 3D, ... box and 0 otherwise.
When the lower and/or upper boundary parameters are scalars, the indexes (I) at lowerb and upperb in the above formulas should be omitted.

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);

Resources