OpenCV findContours destroying source image - opencv

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.

Related

object and contour detection in an image

I am new to image processing and trying to get the contours of the apples in these images. To do so, i use openCV. But i do not get a propper contour detection. I want the algorithm also be able to get contours of other objects. So not limmited to apples (= circles).
Original picture
If i follow the instructions there are 4 steps to be taken.
Open the image file
Convert the file to grayscale
Do some processing (blur, errode, dillitate, you name it)
Get the contours
The first point that confuses me is the grayscale conversion.
I did:
Mat image;
Mat HSVimage;
Mat Grayimage;
image = imread(imageName, IMREAD_COLOR); // Read the file
cvtColor(image, HSVimage, COLOR_BGR2HSV);
Mat chan[3];
split(HSVimage, chan);
Grayimage = chan[2];
First question:
Is this correct choice, or shoud i just read the file in Grayscale or use YUV ?
I only use 1 channel of the HSV, is this correct ?
I tried alot of processing methodes, but there are so many i lost track. The best result i got was when i used a treshold and an adaptiveTreshold.
threshold(Grayimage, Grayimage,49, 0, THRESH_TOZERO);
adaptiveThreshold(Grayimage, Tresholdimage, 256, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 23, 4);
The result i get is:
result after processing
But a find contours does not find a closed object. So i get:
contours
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(Tresholdimage, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
I tried hough cicles,
vector<Vec3f> circles;
HoughCircles(Tresholdimage, circles, HOUGH_GRADIENT, 2.0, 70);
and i got:
hough circles ok
So i was a happy man, but as soon is i tried the code on an other picture, i got:
second picture original
hough circles wrong
I can experiment with the HoughCircles function i see there are alot of posibilities, but i can only detect circles with it, so it is not my first choice.
I am a newbie at this. My questions are:
Is this a correct way or is it better to use technics like blob detection or ML to find the objects in the picture ?
If it is a correct way, what functions should i use to get the better results ?
Regards,
Peter

opencv: Please help me to find out the grid of carton

This question has been annoying me over 2 weeks.
My goal is to analyze a set of products stored in cartons on a shelf.
Right now, I have tried using the following methods from OpenCV Python module: findContours, canny,HoughLines,cv2.HoughLinesP, but I can't find the result grid.
My goal is to check if the products been filled up in carton.
Here is the original image: http://postimg.org/image/hyz1jpd7p/7a4dd87c/
My first step is to use closing transformation:
closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel, iterations=1)]
This gives me the contours (I have not enough reputation to post this url, this image is similar with the last image below, but without red lines!).
Finally, the question is, how could I find the carton grid (i.e., the products in it one by one).
I have added the red lines in the image below.
Please give me the hints, thank you very much!
Red lines: http://postimg.org/image/6i0di4gsx/
I've played a little bit with the input and found a way to extract basically the grid with HoughLinesP after thresholding the Hue channel.
edit: I'm using C++, but similar python methods should be available I guess.
cv::Mat image = cv::imread("box1.png");
cv::Mat output; image.copyTo(output);
cv::Mat hsv;
cv::cvtColor(image, hsv, CV_BGR2HSV);
std::vector<cv::Mat> hsv_channels;
cv::split(hsv, hsv_channels);
// thresholding here is a little sloppy, maybe you have to use some smarter way
cv::Mat h_thres = hsv_channels[0] < 50;
// unfortunately, HoughLinesP couldnt detect all the lines if they were too wide
// to make this part more robust I would suggest a ridge detection on the distance transformed image instead of 'some erodes after a dilate'
cv::dilate(h_thres, h_thres, cv::Mat());
cv::erode(h_thres, h_thres, cv::Mat());
cv::erode(h_thres, h_thres, cv::Mat());
cv::erode(h_thres, h_thres, cv::Mat());
std::vector<cv::Vec4i> lines;
cv::HoughLinesP( h_thres, lines, 1, CV_PI/(4*180.0), 50, image.cols/4, 10 );
for( size_t i = 0; i < lines.size(); i++ )
{
cv::line( output, cv::Point(lines[i][0], lines[i][1]),
cv::Point(lines[i][2], lines[i][3]), cv::Scalar(155,255,155), 1, 8 );
}
here are the images:
hue channel after hsv convert:
threshholded hue channel:
output:
maybe someone else has an idea how to improve the HoughLinesP without those erode steps...
Hope this method helps you a bit and you can improve it further to use it for your needs.

How to determine if a rectangle is well formed using open cv

I am currently trying to determine if a rectangle is well formed such as having perfect corners and straight lines.
This is what I am currently doing now to detect a rectangle
Mat image;
image = imread(argv[1], CV_LOAD_IMAGE_COLOR);
cvtColor( image,image1, CV_BGR2GRAY );
Canny( image1, canny_output,130, 200 );
vector<Point> approx;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE, Point(0,0) );
for (unsigned int i=0; i<contours.size(); i++){
if((approx.size() == 4)){
cout<<"It is a rectangle"<<endl;
}
}
I can detect if it is a rectangle but I am not sure how to detect that is a not a well formed rectangle like the images below.
If the test images are like the ones that you have posted here, you could try to use Hough Transform, firstly to detect the lines and the check if the lines are parallel.
Try to have a look how to use OpenCV Hough Transform implementation on on OpenCV here.
However I need more informations to clarify better the answer.
I also checked there are some others threads about this problem you could check the following:
Hough transformation vs Contour detection for Rectangle recognition with perspective projection
Rectangle detection with Hough transform.
Moreover if you are familiar with research, have a look to this paper.

findContours for blob finding

I'm using OpenCV's findContours() for blob-finding, by floodfilling at an arbitrary seed point in the contour and taking the bounding rectangle of the floodfill. However, when two blobs touch at a corner, e.g.
they share a contour, so only one of the two blobs will be floodfilled, depending on which seed point was chosen.
I could change the floodfill connectivity setting from 4 to 8, so that the blobs are fused in the floodfill. What I'd really like to do instead is ignore the small defect and count only the big blob. Can this be done without substantially changing the algorithm?
Unlike for floodfill, there's no way to use findContours with 4-connectivity natively in OpenCV.
You should take a look at findContours() documentation.
findContours can return multiple contours if they appear in the image, in your case, if you choose 4-connectivity, you should get 2 contours, and then you can compare their bounding box size to decide which one to keep.
cv::Mat img = cv::imread('test.png', 0);
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(img, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
for (size_t i = 0;i < contours.size(); ++i) {
cv::Rect bbox = cv::boundingRect(contours[i]);
std::cout<<"Contour"<<i<<" Area"<<bbox.area()<<std::endl;
}
Hope this helps.

findContours in opencv with "System.AccessViolationException"

I am trying to use the findContours function in Opencv2.4.4 with VS2010express(C++) the code is below.
Mat canny_output;
std::vector > contours;
/// Detect edges using canny
Canny( src_gray, canny_output, 100, 200, 3 );
/// Find contours
threshold(canny_output,canny_output,0,255,THRESH_BINARY);
findContours( canny_output, contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE );
but the program will always trigger breakpoint at the last line with the system error System.AccessViolationException.
Anyone has any idea?
Suggestions:
make sure contours is vector< vector<Point> >
After a Canny operation you can directly feed the edges to findContour..why are you doing a thresholding? that too with a threshold value of zero...skip that line...because the output of canny is a binary image.
Make sure cannny_output is also a gray image.
EDIT: try this ..although this gives external contours..check wether findcontour is orking or not..
findContours(canny_output,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE,Point())

Resources