Quick and easy connected component (blob) using OpenCV

Last Updated on June 30, 2015 by nghiaho12

UPDATE: June 2015

Check the link below to see if it meets your need first.

http://docs.opencv.org/3.0-beta/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=connectedcomponents#connectedcomponents


 

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 …

89 thoughts on “Quick and easy connected component (blob) using OpenCV”

      1. 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

  1. 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

    1. replace all vector with std::vector, or put ‘using namespace std;’ at the top of the file.

  2. 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

    1. 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.

  3. 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

  4. 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?

    1. 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!

  5. 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

    1. The function returns std::vector < std::vector > &blobs. To find the size of a blob do

      blobs[i].size(), for the i-th blob.

      1. 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

        1. 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?

  6. 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.

    1. 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?

    2. 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;
      }
      }

  7. 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!

    1. It has to be of type CV_8U (single channel grey), the intensity at each pixel has to be either 0 or 1.

      1. Thus I need to change this line in findBlob function:

        binary.convertTo(label_image, CV_32UC1);

        and replace CV_32UC1 with CV_8U?

        1. Actually having a look at the code it does this internally already. What version of OpenCV are you using?

          1. Okay that version is too old, hence why you are getting the error. You need OpenCV 2.4.x.

  8. 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.

  9. 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

          1. 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.

          2. Might be some confusion. Are you using my blob.cpp and renaming your file to blob.png?

          3. black instead of white and blue instead of black and The output is a black image

          1. Remove the img / 255 suggestion, and do this

            1. invert the image, eg. img = 255 – img;
            2. run the code as normal

      1. Load your image as greyscale

        Mat carPlate = imread(path, CV_LOAD_IMAGE_UNCHANGED);

        change to

        Mat carPlate = imread(path, 0);

          1. 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.

  10. 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

    1. 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.

      1. 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.

          1. 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….

  11. 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!

  12. 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!

    1. 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].

  13. 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.

    1. 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]

      1. 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.

  14. 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?

    1. 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.

  15. 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!

    1. 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’.

  16. 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

Leave a Reply to Rohit Cancel reply

Your email address will not be published. Required fields are marked *