# Result issues with findContours

Hi all !

I'm kind of new to opencv, and on top of that, I'm french, so, sorry =) I'm using opencv 2.4.1 with visual studio 2008 and i'm having issues with my detection program. I've an image on which there are fishes that I want to detect. I do all the stuff to have an image on which I can work (threshold, dilate, erode...)and then I use Canny and findContours, this is when it gets weird : There are 5 fishes on the image, but the message tells me there are 12404 fishes oO 12404 corresponds to contours.size() Just before, I draw those "contours", and I can clearly see my 5 fishes with their contour drawn in red. So why do I have those 5 drawn contours, but 12404 fishes ?! I'v spent so many time searching and trying anything else but unsuccessfully. Here is the part of my code corresponding :

//**Edges detection
Canny (imde,imcanny,75,150,3);
imshow("cont",imcanny);
cvWaitKey();

//**Contours finding and drawing = way number 1
static vector'<'vector'<'Point'>'> contours; //There ar no '' around < in my code,
//it's just for you to see (html code hides what's in '<>')
findContours(imcanny,contours,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
drawContours(immat,contours,-1,CV_RGB(255,0,0),2);

//**Récupération et affichage du nombre de poissons détectés
char msg[20];
sprintf(msg, "Found %d fishes",contours.size());
printf(msg);
//putText(imcanny,msg,cvPoint(2,12),FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255,0,0));
imshow("cont",immat);
cvWaitKey();

I don't know what I'm doing wrong, I've used exactly what is used in the "coins counting" tutorial so... Thanks a lot for your help Tell me if you need to see another part of my code, or the images maybe, and I'll edit =) Thanks

EDIT 1 :

Here is what I do to the image just before Canny :

//**Lissage de l'image
medianBlur(immat,immat,5);
imshow("binaire",immat);
cvWaitKey();

//**Binarisation de l'image
threshold(immat,imthresh,75,255,CV_THRESH_BINARY);
imshow("binaire",imthresh);
cvWaitKey();*

//**Dilatation de l'image
int dilatation_size=1; //dilatation max=21
Mat element=getStructuringElement(MORPH_RECT, Size(2*dilatation_size+1,2*dilatation_size+1), Point(dilatation_size,dilatation_size));
dilate(imthresh,imde,element);
imshow("dne",imde);
cvWaitKey();

//**Erosion de l'image
int erosion_size=1; //erosion max=21
Mat elementt=getStructuringElement(MORPH_RECT, Size(2*erosion_size+1,2*erosion_size+1), Point(erosion_size,erosion_size));
erode(imde,imde,elementt);
imshow("dne",imde);
cvWaitKey();

EDIT 2

Here are some images :

The very first one, taken from a video :

The one after "cvtcolor" & "medianblur" :

The one after "threshold", "dilate" & "erode" :

The one after "findcontours" and "drawcontours" (bold black) with CV_RETR_LIST :

And the one after "findcontours" and "drawcontours" (bold black) if I use CV_RETR_EXTERNAL instead of CV_RETR_LIST :

In both case I've got my lovely message "found 12404 fishes", this value doesn't change whatever I do...

edit retag close merge delete

Sort by » oldest newest most voted

I don't know about your images. So maybe my answer will be wrong, but if these fishes don't consist solely of an outer contour, then you use the wrong parameter for findContours: CV_RETR_LIST will give you all contours, also those of e.g. the eyes of the fish. So either you search then for your largest contours in your contours-list or you use CV_RETR_EXTERNAL which gives you just the extremal outer contours.

EDIT

I find exactly the 5 contours using your black and white image from above:

with the following code:

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

int main( int argc, char** argv )
{
CV_Assert(!immat.empty());

cv::Mat img;
cv::cvtColor(immat, img, CV_BGR2GRAY);

cv::Mat imcanny;
cv::Canny (img,imcanny,75,150,3);

std::vector<std::vector<cv::Point> > contours;
cv::findContours(imcanny,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE);
cv::drawContours(immat,contours,-1,CV_RGB(255,0,0),2);

std::cout << "found " << contours.size() << " contours\n";
cv::imwrite("contours.png", immat);
}


One of your conversions must be wrong, hope you'll figure it out!

more

Just before "findcontours" I use "threshold" so my image is in black and white (background in white, and the fishes in black, completly), so the eyes or whatever are not "seen". I tried CV_RETR_EXTERNAL instead of CV_RETR_LIST but then I use "drawcontours", and the only contour drawn is in fact the contour of the image, the contour of the fishes are not detected anymore. I'll edit my post to show some images. Plus, I have only one contour, but, the result still says "Found 12404 fishes" haha xD weird... But thank you ;)

( 2013-03-14 02:59:36 -0500 )edit

( 2013-03-14 04:00:28 -0500 )edit

I've tried your code (with no other code around and the image for argv, I suppose it's what you did), and I've got an error "Exception non gérée à 0x... (msvcr90.dll) dans essais.exe : 0x... : Violation d'accès lors de la lecture de l'emplacement 0x..." = Reading access violation. And nothing else. A yellow arrow points "if (*file==_T('\0'))" in the "fopen.c" file, and I have a table "Nom = *file / Valeur = 0 / Type = const char". I suppose there's a problem when opening the image but, why ? I remember I wanted to use imread in my code, but it didn't work (same error) so I do this : "immat=cvCreateMat(im->height, im->width, CV_32FC1); Mat immat(im);" which works. Why do I have this problem with imread ?! Thanks

( 2013-03-14 04:50:47 -0500 )edit

Something in your visual studio+opencv environment is wrong. Since I am neither using windows nor visual studio I can't tell you what it is. Maybe you can create another question here in the Q&A forum with this error.

Which library do you use then for reading in your image? And why do you use CV_32FC1? Maybe this is the reason why you got so many troubles.

( 2013-03-14 07:29:40 -0500 )edit

I use CV_32FC1 because I've done ctrl+c -> ctrl+v from a tutorial I guess xD but, I see, I've changed for CV_8UC1, and now I have 12409 fishes, instead of 12404 xD I'll create a new question then. I suppose I've got a problem in my environment, but, I've checked manytimes where there could be something wrong, and I don't find anything of that kind so, I don't know. But thanks ;)

( 2013-03-14 10:23:18 -0500 )edit

Did my example not work? Do you need the used headers? I'll update the complete example. Why one channel instead of three? If you actually have a three-channel image but say it is a one-channel image your output will get weired results.

( 2013-03-14 11:19:39 -0500 )edit

Hey ! I'm back ! My "imread" problem is now solved, all my code is written in C++ style, and it works =) the debug mode wasn't configured properly. Now if I run my program, I have finally, 10 fishes, instead of 12404. It's still too many but it's much better =) I'll try to have my 5 fishes with your help, and I'll comment to give my results =) thanks ;)

( 2013-03-15 05:19:11 -0500 )edit

Me again, it works ! I have my lovely message "found 5 fishes" ! so great ! Thank you very much ! ^^ My problem is solved hehe =)

( 2013-03-15 05:27:28 -0500 )edit

NeVrOzAy: I have a similar problem with findContour method behaviour, could you please tell about how you configurate debug mode in Visual Studio? thanks)

( 2013-06-15 21:26:40 -0500 )edit

there's a couple of things you can do

1. blurring ( sounds counterintuitive, but if that's the first step you do, even before the binarizing, you'll filter out all the bubbles, noize, etc )

e.g. blur(img,img,Size(5,5));

2. try something else for binarizing. if the contrast between the fish and the surrounding is high enough, you don't actually need an Edge filter like Canny or Sobel, but a simple threshold will work much nicer. Edge filters tend to break the contours into small pieces, also every line has an inner and an outer edge then.

e.g. threshold(img,img,128,255,0);

more

Thanks, I edited my post, as you can see, I blur the image just before threshold ;) and the threshold is simple. I've tried to use findcontours directly (so without Canny), but I've got an error about the format of the image if I've understood --' and now, I'm lost xD

( 2013-03-13 11:02:57 -0500 )edit

at which operation do you get the error ?

( 2013-03-13 11:07:06 -0500 )edit

oh misread. it needs a uc8 grayscale as input! ( seems, you're doing all of it in color ? ) so before anything else, put: Mat grey, cvtColor(im,gray,CV_BGR2GRAY); and use that as input for medianBlur

( 2013-03-13 11:13:21 -0500 )edit

The image is taken from a video recorded by a monochrome camera, thought it was already in grayscale but apparently not, I don't have this error anymore now, thank you =) but I still have my message "Found 12404 fishes" instead of 5. I'll try what "Guanta" says in his answer ;)

( 2013-03-14 02:47:58 -0500 )edit

Official site

GitHub

Wiki

Documentation