Last Updated on June 30, 2015 by nghiaho12
UPDATE: June 2015
Check the link below to see if it meets your need first.
OpenCV is up to version 2.3.1 and it still lacks a basic connected component function for binary blob analysis. A quick Google will bring up cvBlobsLib (http://opencv.willowgarage.com/wiki/cvBlobsLib), an external lib that uses OpenCV calls. At the time when I needed such functionality I wasn’t too keen on linking to more libraries for something so basic. So instead I quickly wrote my own version using existing OpenCV calls. It uses cv:floodFill with 4 connected neighbours. Here is the code and example input image
UPDATE: 22th July 2013
I got rid of the hacks to work with OpenCV 2.3.1. It should now work with OpenCV 2.4.x.
On Linux, you can compile it using:
g++ blob.cpp -o blob -lopencv_core -lopencv_highgui -lopencv_imgproc
The results …
beautiful code… will be trying it out on a project…thank you
Hi,
I was googling around to see if people are still searching on how to do connected components since I created a new easy method in opencv… you came up on google. Please have a look here for a very simple/fast way of computing 4 and 8 way.
http://code.opencv.org/attachments/467/opencv-connectedcomponents.patch
Thanks for the news. Has it been accepted into the trunk?
pending, ticket here http://code.opencv.org/issues/1236
It’s a builtin to OpenCV 3.0 – please update your article pointing to this way of doing it in 3.0+:
http://docs.opencv.org/3.0-beta/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=connectedcomponents#connectedcomponents
Thank you for maintaining your solution all these years but we need to make sure newbies stop getting sucked into the various implementation and their shortcomings for one consistent (fast) way of doing it. To introduce to the frontlines of students/etc I need the help of the various high-rank hits on google, which you are a long time high result to spread the message.
Thanks,
Jason
goodevening
i am tryig to use ur code in my projects and facing problems in the building stage …wish u can help me …that some kinds of the erros i recieve :
error C2783: ‘_Tp &cv::Mat::at(int,int)’ : could not deduce template argument for ‘_Tp’
1> c:\opencv-2.1.0\include\opencv\cxcore.hpp(895) : see declaration of ‘cv::Mat::at’
error C2783: ‘const _Tp &cv::Mat::at(int,int) const’ : could not deduce template argument for ‘_Tp’
1> c:\opencv-2.1.0\include\opencv\cxcore.hpp(897) : see declaration of ‘cv::Mat::at’
error C2228: left of ‘.y’ must have class/struct/union
error C3203: ‘vector’ : unspecialized class template can’t be used as a template ar
std::vector’ : use of class template requires template argument list
replace all vector with std::vector, or put ‘using namespace std;’ at the top of the file.
hi nghiaho12
i tried to do so even before ,but with no diference…..
may i have your e-mail or skype or any other faster way to contact you…its verry important to me to use
your code in my project.
thanks anyway for trying to help me
To solve the problem some of you are getting, you need to do do a couple of change:
std::vector blob; —–> std::vector blob;
if((int)label_image.at(y,x) != 1) { —-> if((int)label_image.at(y,x) != 1) {
if((int)label_image.at(i,j) != label_count) { —-> if((int)label_image.at(i,j) != label_count) {
This should fix your issue with the compiler unable to deduce the template argument.
Hi,
I copied latest version of cvblob from http://code.google.com/p/cvblob/
I used cmake to build it. when I compile the code I am getting the following error
LINK : fatal error LNK1104: cannot open file ‘..\lib\Debug\cvblob.lib’
There is no library file in the path. Please let me know how to resolve the error.
Thanks
Mahesh
That is not my code. You’ll have to ask the author for help.
Is there a way to compile this under Linux?
It looks like I can only compile pure C code… I am getting this errors when trying to compile:
test01.c:26: error: type/value mismatch at argument 1 in template parameter list for ‘template class std::vector’
test01.c:26: error: expected a type, got ‘vector’
test01.c:26: error: template argument 2 is invalid
test01.c:26: error: invalid type in declaration before ‘;’ token
test01.c:30: error: ‘FindBlobs’ was not declared in this scope
am I doing something wrong or it only works on Windows?
Due to some annoying HTML issues messing up with the displaying of the code, I’ve posted it up for download. Should have done that from the beginning!
Hi,
I have one image showing different smaller objects of irregular sizes. By using blob detection codes provided by you, I can able to get the labelled image clearly but I couldn’t obtain total counting of those smaller labelled objects in numbers.
Can you guide me in this matter?
Thank You
The function returns std::vector < std::vector > &blobs. To find the size of a blob do
blobs[i].size(), for the i-th blob.
I beg your pardon but my doubt is to “Count Total Number of Labelled Blobs” of the image in numbers like I should get total numbers of blobs as 30 or 40 or more.
Is determining size of blobs suggested by you solve this problem?
Please guide me again as this task is very important for me to understand and implement it completely.
Thank You
I’m a bit unclear what you’re asking. The function returns std::vector < std::vector > &blobs, which allows you to do:
cout << "Total blobs found: " << blobs.size() << endl; for(size_t i=0; i < blob.size(); i++) cout << "Blob " << i << " size is: " << blob[i].size() << endl; Is this what you are looking for?
It works pretty well. I”m trying to extract largest blob and output it in a new window. Do you have any idea how to do it?
blob.size() vs. blobs[i].size() ?? I’m confused because I just couldn’t understand or picture vectors…vector conceived in another vector.
in terms of vectors… where is the start of blob point and where is the end of it? blobs[i][j] or is it a blob vector inside blobs[i][j] cell?
Think of it as a 2D array. The first index loops through the blob, the second index loops through the blob’s co-ordinates.
For your task do
size_t max_pixels = 0;
size_t max_at = 0;
for(size_t i=0; i < blobs.size(); i++) { if(blobs[i].size() > max_pixels) {
max_pixels = blobs[i].size();
max_at = i;
}
}
Hello,
I am wiling to use your code for a project concerning object detection and recognition.
“Blob.cpp” does exactly what I need but unfortunately I can’t get it to work… I am stuck with this error:
OpenCV Error: Unsupported format or combination of formats () in cvFloodFill, file /build/buildd/opencv-2.3.1/modules/imgproc/src/floodfill.cpp, line 1046
terminate called after throwing an instance of ‘cv::Exception’
what(): /build/buildd/opencv-2.3.1/modules/imgproc/src/floodfill.cpp:1046: error: (-210) in function cvFloodFill
I know that this means that cv::FloodFill doesn’t get the parameters he wants (the right type) but I can’t find which parameters is wrong (I didn’t change anything to your code)…
Can you give me a hint?
Thank you in advance!
It has to be of type CV_8U (single channel grey), the intensity at each pixel has to be either 0 or 1.
Thus I need to change this line in findBlob function:
binary.convertTo(label_image, CV_32UC1);
and replace CV_32UC1 with CV_8U?
Actually having a look at the code it does this internally already. What version of OpenCV are you using?
I am using OpenCV 2.3.1
Okay that version is too old, hence why you are getting the error. You need OpenCV 2.4.x.
Thank you. Your code works great. It is annoying that OpenCV does not have ConnectedComponent function, even though the OpenCv2.4.9 has the doccument for it.
I agree. It’s weird they still don’t have one after all this time!
Hi, I just used your code, with a couple of changes to make it fit in my app, and it works very well. Now I’m trying to understand it, what is this line for: “int *row = (int*)label_image.ptr(y);” and this one: “int *row2 = (int*)label_image.ptr(i);”.
Thanks
Just a shorthand to get an int pointer to row “y” of the image.
Oh, got it… Thank you, your code has been very useful.
Thanks a million, Nghia Ho! You are my hero today
🙂
didn’t work with my image, do you know the reason?
my image: http://imagizer.imageshack.us/a/img819/7572/lq1l.png
Divide the image by 255, it has to range from [0,1].
I don’t understood, you can demonstrate in code?
cv::Mat img …
img = img / 255;
or
img = img * (1/255.0)
this informattion could be useful I want to remove the black borders in this image:
https://imageshack.com/i/mrlq1lp
the image after img = img / 255;
https://imageshack.com/i/n6p0bbp
the output of function:
https://imageshack.com/i/mv2bykp
Your last image has strange colors, why is that?
I don’t know!!
I want to remove the black borders, you have another idea to do it?
Have a look at my example code and see how it works. Once you got it segmented correctly, you can select the region that contains the pixel in the top left corner.
I’m using your code, and its is the result:
the image after img = img / 255;
https://imageshack.com/i/n6p0bbp
the output of function:
https://imageshack.com/i/mv2bykp
Might be some confusion. Are you using my blob.cpp and renaming your file to blob.png?
black instead of white and blue instead of black and The output is a black image
I get this
I’m using your code blob.cpp with my image.
Remove the img / 255 suggestion, and do this
1. invert the image, eg. img = 255 – img;
2. run the code as normal
I change the code to one function: https://www.dropbox.com/s/ektslj6t2yr6pey/Clean.cpp
whats wrong?
Load your image as greyscale
Mat carPlate = imread(path, CV_LOAD_IMAGE_UNCHANGED);
change to
Mat carPlate = imread(path, 0);
still does not identify blog
My sample code blob.cpp works perfectly on your image, I only added
img = 255 – img;
after loading the image.
Check my code workson your machine first.
Hi,
Your routine is awesome! I can successfully get a set of blobs that are 4-way connected. To reduce noise in an binary image. I also need to run a second pass at an 8-way connection to do a solidity analysis. By modifying the flood-fill parameter (to 8) it doesn’t seem to produce correct results. Is there something else I’m missing…
Regards,
allan
There’s very little difference between the 4 and 8 in theory. The 8 is able to connect two blobs joined on the diagonal by a single pixel, where as the 4 can’t. That’s like the edge casse. Every other situation they both should produce more or less the same results.
Can you point in the right direction in modifying your function to be able to do a 8 way or a 4 way? I thought it would be as simple as changing the floodfill parameter from 4 to 8… I’ve read the wiki page on Connected-component_labeling … but it is a bit over my head.
You did it correctly. I’m just saying don’t expect to see any difference between 4 and 8 in your results.
The difference I’m seeing is in the Blob Size. I thought I’d see a reduction in the number of blobs because a couple would “merge” together based, instead it merges more blobs together than expected….
i replace CV_32UC1 with CV_8U … because i have the same error –> (Kateline)
the image result is black (i used your image blob.png)
i have the opencv2.4.9
Please help me :'(
Thank you in advance!
Are you 100% you are linking to opencv 2.4.9 and no other version on the system?
your library is too slower than OPENCV 2.4.9’s findcontours..
please delete this article..
mmm nah
Thank you for your code. It works well. After component labeling, I would like to apply the Harris coner detector to the pixel blobs for EACH labeled component SEPERATELY. Could you should me how to do that? Thanks!
And how to extract one blob and output & display in a separate new window?
Umm not sure how to do what you want, but the blobs are stored as vector> blobs, so blobs[0] contains the pixel locations for blobs[0].
Nice piece of code, and it works perfectly.. Thank you!
Hey its a really nice code.
may I ask how can I find only blobs bigger than X,Y size in this piece code ? because on my image I get a lot of labels.
You can find the bounding box by looping over the pixels inside the array
vector> blobs
blobs[0] <-- loop over this vector and find the min/max (x,y) do the same for the blobs[i]
Thank you!
You saved me a lot of time!
It works very well,
Great code!!
Hi, Its really awsome. But its working only for binary image. Isn’t it.
How can i assign the label for segmented image without any gaps.
here is my image
https://imageshack.com/i/eyCfkedBp
How can i give label id for each color. Please help me to resolve this issue
How can i take each segment(each color) one by one separately?
https://imageshack.com/i/eyCfkedBp
Ummm just use some lookup table. Visit each pixel, add a new entry with a new ID if that color hasn’t been seen before.
Hi, i test your code . what i get at print out is that the blobs.size() is always 0 for some reasons. Can you clarify this please?
Did you test with my sample image? If it still returns zero then OpenCV has changed API and my code no longer works with their stuff.
Hello.
I dont understand this part of the program.
Can you explain it to me?
for(int i=rect.y; i < (rect.y+rect.height); i++) {
int *row2 = (int*)label_image.ptr(i);
for(int j=rect.x; j < (rect.x+rect.width); j++) {
if(row2[j] != label_count) {
continue;
}
and thanks!
The floodfill returns a rect of the blob. I’m looping over the rect region to figure out which pixel belongs to the blob, with label ‘label_count’.
Can you explain “rect” ?
Rect has the same meaning as cv::Rect from OpenCV
Very Helpful, Thanks
Thanks you, works perfect
How to draw a square for each label?!
Thank you
loop through the pixels and find the min and max
Ok thank you.
Can you help me please to determine this task, I tried but I do not find the trick
no, you’ll figure it out eventually
thare many ways to do it,, i particularly did for green color tracking , what is important is to give a unique IDs to the blob which can make the tracked blob different from rest in the enviroment,, i dont know how to approach for this…
though according to me giving kalman filter to each blob my camera sees can work (not sure) ,,
does any one know any simple method to give a unique id to the blob .. (cpp and opencv )
thanks
any particular comment can mail me on my id kzbr1993@gmail.com
any source for Python
Thanks!
I don’t have a Python version.