Blob Detection Using OpenCV ( Python, C++ )

By | February 17, 2015

OpenCV Blob Detection Example
This tutorial explains simple blob detection using OpenCV.

What is a Blob ?

A Blob is a group of connected pixels in an image that share some common property ( E.g grayscale value ). In the image above, the dark connected regions are blobs, and the goal of blob detection is to identify and mark these regions.

SimpleBlobDetector Example

OpenCV provides a convenient way to detect blobs and filter them based on different characteristics. Let’s start with the simplest example

Python

# Standard imports
import cv2
import numpy as np;

# Read image
im = cv2.imread("blob.jpg", cv2.IMREAD_GRAYSCALE)

# Set up the detector with default parameters.
detector = cv2.SimpleBlobDetector()

# Detect blobs.
keypoints = detector.detect(im)

# Draw detected blobs as red circles.
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures the size of the circle corresponds to the size of blob
im_with_keypoints = cv2.drawKeypoints(im, keypoints, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

# Show keypoints
cv2.imshow("Keypoints", im_with_keypoints)
cv2.waitKey(0)

C++

using namespace cv;
// Read image
Mat im = imread( "blob.jpg", IMREAD_GRAYSCALE );

// Set up the detector with default parameters.
SimpleBlobDetector detector;

// Detect blobs.
std::vector<KeyPoint> keypoints;
detector.detect( im, keypoints);

// Draw detected blobs as red circles.
// DrawMatchesFlags::DRAW_RICH_KEYPOINTS flag ensures the size of the circle corresponds to the size of blob
Mat im_with_keypoints;
drawKeypoints( im, keypoints, im_with_keypoints, Scalar(0,0,255), DrawMatchesFlags::DRAW_RICH_KEYPOINTS );

// Show blobs
imshow("keypoints", im_with_keypoints );
waitKey(0);

How does Blob detection work ?

SimpleBlobDetector, as the name implies, is based on a rather simple algorithm described below. The algorithm is controlled by parameters ( shown in bold below )  and has the following steps. Scroll down to know how the parameters are set.

  1. Thresholding : Convert the source images to several binary images by thresholding the source image with thresholds starting at minThreshold. These thresholds are incremented  by thresholdStep until maxThreshold. So the first threshold is minThreshold, the second is minThreshold thresholdStep, the third is minThreshold + 2 x thresholdStep, and so on.
  2. Grouping : In each binary image,  connected white pixels are grouped together.  Let’s call these binary blobs.
  3. Merging  : The centers of the binary blobs in the binary images are computed, and  blobs located closer than minDistBetweenBlobs are merged.
  4. Center & Radius Calculation :  The centers and radii of the new merged blobs are computed and returned.

Filtering Blobs by Color, Size and Shape

The parameters for SimpleBlobDetector can be set to filter the type of blobs we want.

  • By Color : [ Note : This feature appears to be broken. I checked the code, and it appears to have a logical error ]  First you need to set filterByColor = 1. Set blobColor = 0 to select darker blobs, and blobColor = 255 for lighter blobs. 
  • By Size :   You can filter the blobs based on size by setting the parameters filterByArea = 1, and appropriate values for minArea  and maxArea. E.g.  setting minArea  = 100 will filter out all the blobs that have less then 100 pixels.
  • By Shape : Now shape has three different parameters.
    1. Circularity :  This just measures how close to a circle the blob is. E.g. a regular hexagon has higher circularity than say a square. To filter by circularity, set filterByCircularity = 1.  Then set appropriate values for minCircularity and maxCircularity.  Circularity is defined as

      \frac{4*\pi*Area}{perimeter * perimeter}

      This means that a circle has a circularity of 1, circularity of a square is 0.785, and so on.

    2. Convexity : A picture is worth a thousand words.  Convexity is defined as the (Area of the Blob / Area of it’s convex hull). Now, Convex Hull of a shape is the tightest convex shape that completely encloses the shape.  To filter by convexity, set filterByConvexity = 1, followed by setting 0 ≤ minConvexity ≤ 1 and maxConvexity ( ≤ 1) Concave versus Convex Shape
    3. Inertia Ratio : Don’t let this scare you. Mathematicians often use confusing words to describe something very simple. All you have to know is that this measures how elongated a shape is. E.g. for a circle, this value is 1, for an ellipse it is between 0 and 1, and for a line it is 0. To filter by inertia ratio, set filterByInertia = 1and set 0 ≤ minInertiaRatio ≤ 1 and maxInertiaRatio (≤ 1 ) appropriately. Inertia Ratio

How to set SimpleBlobDetector params ?

Setting parameters for SimpleBlobDetector is easy. Here is an example

Python

# Setup SimpleBlobDetector parameters.
params = cv2.SimpleBlobDetector_Params()

# Change thresholds
params.minThreshold = 10;
params.maxThreshold = 200;

# Filter by Area.
params.filterByArea = True
params.minArea = 1500

# Filter by Circularity
params.filterByCircularity = True
params.minCircularity = 0.1

# Filter by Convexity
params.filterByConvexity = True
params.minConvexity = 0.87

# Filter by Inertia
params.filterByInertia = True
params.minInertiaRatio = 0.01

# Create a detector with the parameters
ver = (cv2.__version__).split('.')
if int(ver[0]) < 3 :
	detector = cv2.SimpleBlobDetector(params)
else : 
	detector = cv2.SimpleBlobDetector_create(params)

C++

Setting of params for SimpleBlobDetector in OpenCV 2 is slightly different from OpenCV 3. In the code below we use the macro CV_MAJOR_VERSION to detect the version of OpenCV. In OpenCV 3, the SimpleBlobDetector::create method is used to create a smart pointer. The usage is shown in the code below.


// Setup SimpleBlobDetector parameters.
SimpleBlobDetector::Params params;

// Change thresholds
params.minThreshold = 10;
params.maxThreshold = 200;

// Filter by Area.
params.filterByArea = true;
params.minArea = 1500;

// Filter by Circularity
params.filterByCircularity = true;
params.minCircularity = 0.1;

// Filter by Convexity
params.filterByConvexity = true;
params.minConvexity = 0.87;

// Filter by Inertia
params.filterByInertia = true;
params.minInertiaRatio = 0.01;

#if CV_MAJOR_VERSION < 3   // If you are using OpenCV 2

  // Set up detector with params
  SimpleBlobDetector detector(params);

  // You can use the detector this way
  // detector.detect( im, keypoints);

#else

  // Set up detector with params
  Ptr<SimpleBlobDetector> detector = SimpleBlobDetector::create(params);

  // SimpleBlobDetector::create creates a smart pointer. 
  // So you need to use arrow ( ->) instead of dot ( . )
  // detector->detect( im, keypoints);

#endif

Download code & example image

If you liked this article and would like to get more OpenCV tips, tricks, examples and tutorials in your email, sign up using the blue top bar. Some of my material is exclusive for email subscribers. My emails are meant for beginners and intermediate level OpenCV programmers who want to learn more.

Click OpenCV blob detector to download code (C++, Python, and example image) from GitHub. The image included in the download link can be used to test various parameters, as shown below.

Test Area, thresholds, circularity,  inertia, and convexity

Category: how-to Object Detection Tags: , , , ,

About Satya Mallick

I am an entrepreneur with a love for Computer Vision and Machine Learning with a dozen years of experience (and a Ph.D.) in the field. In 2007, right after finishing my Ph.D., I co-founded TAAZ Inc. with my advisor Dr. David Kriegman and Kevin Barnes. The scalability, and robustness of our computer vision and machine learning algorithms have been put to rigorous test by more than 100M users who have tried our products.

  • Jakub Vlk

    Hello, thank you for very interesting article.
    I’m trying to find centre of the eye and I’m using thresholding, eroding, find contours and other features which gave me the best result. However with different light conditions come different results very often.
    I was trying to switch and use this class, but it’s kinda tricky to set up parameters for the best result. You know it’s quite easy to set parameters for static image, but it’s getting harder when you are using webcam and lightning conditions are changing during a day.
    Do you know, if I can some how see the final binary image? I think it will help me with parameters. Thank you for answer, Jakub.

  • michelle plyers

    Hello,

    I am trying to compile the code using cmake. After using make, I receive the errors:
    $> cmake .
    $>make

    home/mitchell/Documents/
    exboneb/bonestuff.cpp: In function ‘int main(int, char**)’:
    /home/mitchell/Documents/exboneb/bonestuff.cpp:32:35: error: no matching function for call to ‘cv::SimpleBlobDetector::SimpleBlobDetector(cv::SimpleBlobDetector::Params&)’
    SimpleBlobDetector detector(params);
    ^
    /home/mitchell/Documents/exboneb/bonestuff.cpp:32:35: note: candidates are:
    In file included from /usr/local/include/opencv2/opencv.hpp:50:0,
    from /home/mitchell/Documents/exboneb/bonestuff.cpp:7:
    /usr/local/include/opencv2/features2d.hpp:468:20: note: cv::SimpleBlobDetector::SimpleBlobDetector()
    class CV_EXPORTS_W SimpleBlobDetector : public Feature2D
    ^
    /usr/local/include/opencv2/features2d.hpp:468:20: note: candidate expects 0 arguments, 1 provided
    /usr/local/include/opencv2/features2d.hpp:468:20: note: cv::SimpleBlobDetector::SimpleBlobDetector(const cv::SimpleBlobDetector&)
    /usr/local/include/opencv2/features2d.hpp:468:20: note: no known conversion for argument 1 from ‘cv::SimpleBlobDetector::Params’ to ‘const cv::SimpleBlobDetector&’
    make[2]: *** [CMakeFiles/bonestuff.dir/bonestuff.cpp.o] Error 1
    make[1]: *** [CMakeFiles/bonestuff.dir/all] Error 2
    make: *** [all] Error 2

    I am having trouble finding documentation and examples on how to use opencv FeatureDetector and SimpleBlobDetector. Your resource seems like the best place to start playing with it but I cannot make the executable.

    thanks

    • Looks like you are using OpenCV 3, and they changed the interface slightly. You will need to make the changes to the following two lines.

      Ptr detector = cv::SimpleBlobDetector::create(params);
      detector->detect( im, keypoints);

      Please let me know if it worked. Thanks! ( I will update the post later today )

      • sophie

        hi….I’m stuck with the same error even after the changes suggested by you.it would be great if you could help and the image is same as yours. the error is like:

        p, li { white-space: pre-wrap; }

        ../blobdetect/main.cpp:65:80: error: no matching function for call to ‘cv::SimpleBlobDetector::create(cv::SimpleBlobDetector::Params&)’

        Ptr detector =cv::SimpleBlobDetector::create(params);

        ^

        In file included from /usr/local/include/opencv2/opencv.hpp:50:0,

        from ../blobdetect/main.cpp:8:

        /usr/local/include/opencv2/features2d.hpp:125:41: note: candidate: static cv::Ptr cv::FeatureDetector::create(const cv::String&)

        CV_WRAP static Ptr create( const String& detectorType );

        ^

        /usr/local/include/opencv2/features2d.hpp:125:41: note: no known conversion for argument 1 from ‘cv::SimpleBlobDetector::Params’ to ‘const cv::String&’

        ../blobdetect/main.cpp: At global scope:

        ../blobdetect/main.cpp:20:15: warning: unused parameter ‘argc’ [-Wunused-parameter]

        int main( int argc, char* argv[] )

        ^

        ../blobdetect/main.cpp:20:32: warning: unused parameter ‘argv’ [-Wunused-parameter]

        int main( int argc, char* argv[] )

    • I have updated the post and the code on Github to reflect my earlier comment.

      If you like the blog, please subscribe to our email list and tell your friends about it :). Thanks.

      • michelle plyers

        Hey thanks for the reply! It successfully compiled with your changes, but it would not execute because I did not install OpenCV with gtk2.0-dev enabled. The original code ended up working on our important machine (beaglebone black), so I will have to make some time later to reinstall OpenCV on the virtualbox that was not working.

        thanks! subscirbed.

  • saher

    Hi,
    Nice article. I am trying to use only filterByCircularity but it alone doesn’t seems to detect even a perfect circle. I have tried it with the min and maximum range but that also does not helps. If I use filter by area in combination with it, it seems to work; because of the area filters i think.
    Can you plz tell me the default values of min and maximum circularity?
    Also have you tried using filterByCircularity alone? does it works for you on any of the image given in ur article?
    params.filterByCircularity = true;
    params.minCircularity = 0.0;
    params.maxCircularity = 1;

    Regards
    Saher Maqsood

    • HI Saher,
      First try the example image I have shared on GitHub ( You can see in the Downloads section above ).

      Second, make sure it is a black blob on a light background and not the other way round.

      • saher

        Hi Satya,
        I tried with your image and your code. Every thing works fine even if I comment out all the filters apart from filterByCircularity.

        Now when I try with another image on your code (an image converted to grayscale from BGR), it doesnot detects it as a circle.

        I have also tried with binary images and both .jpg and .png images.

        I am attaching the image here. Can you please have a look and suggest whats missing?

        • Hi Saher, Could you please attach the image again. I don’t see it here. If that does not work, could you please put a link to the image.

          Thanks.

          • saher

            Hi, I am attaching the image here.Its converted to grayscale from BGR.

          • I think the problem with your example was that the default maxArea is smaller than the area of the ball. Here are the params that worked for me.

            params.minThreshold = 90
            params.maxThreshold = 120

            # Filter by Area.
            params.filterByArea = True
            params.minArea = 100
            params.maxArea = 100000

            # Set other filter options to false.
            params.filterByCircularity = False
            params.filterByConvexity = False
            params.filterByInertia = False
            params.filterByColor = False

          • saher

            Hello,
            The filter by area was in any case working for me. My question was about using filterByCircularity alone. Did that work for you?

  • Axel Straminsky

    Hi, I’m new to OpenCV, and I was trying to do a program that, given a tree of, for example, olives, could detect the amount of olives in the tree, but it’s detecting nonsense basically. The parameters I used are:

    params.minDistBetweenBlobs = 2.0f;

    //To filter leaves.
    params.filterByInertia = true;
    params.minInertiaRatio = 0.0f;
    params.maxInertiaRatio = 0.6f;

    params.filterByConvexity = false;
    params.filterByColor = false;
    params.filterByCircularity = false;

    params.filterByArea = true;
    params.minArea = 10.0f;
    params.maxArea = 22.0f;;

    Could it be that I have to apply some kind of filter first?

    Thanks a lot!

    • Do you have an example image that I can look at ?

      • Axel Straminsky

        Yes, I uploaded one example here: http://s17.postimg.org/ezt2gzren/DSC01345.jpg

        • This image is too complex for the blob detector. Simple blob detector only works on gray scale images where the blobs are dark / easily identifiable.

        • Alexander Stohr

          The image is surely not a black-white one for which basic blob operators are normally designed for.

          Try doing a color-space & histogram analysis to first getting only parts of elevated likelyness for relevancy. The result should be a much more binary image. Then send those “focussed” image to the blob detector.

          A speparate, more costly approach would be a pattern matching method from the field of image processing algorithms, like well known support vector machine designs (SVM) allong with their inter-connected modules. It’s a fuzzy probability approach, but as you know your patterns including the variety spectrum of objects you should be able to succeed training some “neuronal” qualifier/detector network with a sample set. – Just my 2 cents, as i feel it matches better with your problem. (You have a relative small color distance between some of your items of interest and the background: yellow to light green…)

  • Ryan Coxey

    Would it be possible to use this while analyze a live webcam feed. with your coad put somewhere in the following loop:

    v.NamedWindow(“w1”, cv.CV_WINDOW_AUTOSIZE)
    capture = cv.CaptureFromCAM(0)

    def repeat():

    frame = cv.QueryFrame(capture)
    cv.ShowImage(“w1”, frame)

    while True:
    repeat()

    • It is not a very expensive operation. You should be able to do it.

  • Alex Diaz

    Don’t really have any question but i want to thank you for your big efforts on this website!!! I’ll come in the future for further information…

    • Thanks a bunch Alex. I am glad you found it useful.

      • Alex Diaz

        Okey, I am collecting every algorithm I have encountered and SimpleBlob is the only one not working… As I have your help, I ask you, what could have gone bad?

        The error is, detector deos not have a detect attribute.

        First I tried

        detector = cv2.FeatureDetector_create(“SimpleBlob”),

        like any other algorythm(all they working)

        and after I tried what appears on your code

        detector = cv2.SimpleBlobDetector()

        It still says there is no attribute detect.

        My python version is 2.7 and OpenCV 2.4…
        If you can help me, my teacher would be delighted with my entense work and investigation 🙂
        Thanks in advance!

        • Can you cut-paste your exact code here ?

          • Alex Diaz

            Yes: This is the method:

            def getDetector(type=”ORB”):
            detector = None
            if(type==”BRISK”):
            detector = cv2.FeatureDetector_create(“BRISK”)
            if(type==”Dense”):
            detector = cv2.FeatureDetector_create(“Dense”)
            if(type==”FAST”):
            detector = cv2.FeatureDetector_create(“FAST”)
            if(type==”GFTT”):
            detector = cv2.FeatureDetector_create(“GFTT”)
            if(type==”HARRIS”):
            detector = cv2.FeatureDetector_create(“HARRIS”)
            if(type==”MSER”):
            detector = cv2.FeatureDetector_create(“MSER”)
            if(type==”ORB”):
            detector = cv2.FeatureDetector_create(“ORB”)
            if(type==”SIFT”):
            detector = cv2.FeatureDetector_create(“SIFT”)
            if(type==”STAR”):
            detector = cv2.FeatureDetector_create(“STAR”)
            if(type==”SURF”):
            detector = cv2.FeatureDetector_create(“SURF”)
            if(type==”SimpleBlob”):#NO funca
            detector = cv2.SimpleBlobDetector()

            return detector

            As you can see,. I pass a String with the user’s selection and returns the corresponding detector.

            Thank you so much!

          • Alex Diaz

            It’s already working, there was a bug… the stupid program never got to detector = cv2.SimpleBlobDetector() becaus I was passin ‘Simple Blob’ ‘-.-
            Sorry for the inconvenience, best regards!

          • Good. Sometimes explaining your problem to someone helps you see the solution 🙂

      • Willy Loman

        Could someone please tell me how to, (in Python) determine the “NUMBER” of detected blobs?

  • Emrah

    Your tutorial seems quite handy and helpful, but there is a problem. When I try to implement the blob detection algorithms on my previous nvcc (CUDA) program, I got the errors below. Problem is probably with adding the required libraries. Could you please make some suggestions? Thank you.

    orwell2023@orwell2023-TWH:~/Desktop/Tracker$ nvcc motionTracking10.cu -o motionTracking10 -lopencv_core -lopencv_imgproc -lopencv_objdetect -lopencv_highgui

    motionTracking10.cu(94): error: identifier “SimpleBlobDetector” is undefined

    motionTracking10.cu(97): error: identifier “KeyPoint” is undefined

    motionTracking10.cu(103): error: name followed by “::” must be a class or namespace name

    motionTracking10.cu(103): error: identifier “drawKeypoints” is undefined

    4 errors detected in the compilation of “/tmp/tmpxft_00001ad0_00000000-6_motionTracking10.cpp1.ii”.

    • Emrah

      I have fixed the problem by adding;

      #include
      #include
      #include
      #include

      into the program, and using the flags:

      nvcc motionTracking10.cu -o motionTracking10 -arch=sm_21 -w -I/usr/local/include/opencv -I/usr/local/include -L/usr/local/lib -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_contrib -lopencv_legacy -Iutil/

      • Glad that your problem was fixed. Thanks a bunch for posting the solution. Someday your answer will save someone a bunch of time!

        • Emrah

          Thank you Satya. Hope it helps someone in one day 🙂

          By the way symbols =”” above had to be /
          I weren’t able to fix it.

  • Ridvan

    Hello, I want to detect ellipses on a treble staff with using SimpleBlobDetection method of OpenCV but when I try to detect them, it finds unrelated things. Please help me, params and image in below:

    // Filter by Area
    params.filterByArea = true;
    params.minArea = 100;
    params.maxArea = 500;

    // Filter by Circularity
    params.filterByCircularity = true;
    params.minCircularity = 0.1;
    params.maxCircularity = 0.5;

    // Filter by Convexity
    params.filterByConvexity = true;
    params.minConvexity = 0.57;
    params.maxConvexity = 0.97;

    // Filter by Inertia
    params.filterByInertia = true;
    params.minInertiaRatio = 0.01;

    • You have to preprocess the image because the blobs are not isolated. Here is the code in python. The result is attached.

      ======================
      # Standard imports
      import cv2
      import numpy as np;

      # Read image
      im = cv2.imread(“blob.jpg”, cv2.IMREAD_GRAYSCALE)
      im_orig = im

      _, im = cv2.threshold(im, 128, 255, cv2.THRESH_BINARY)

      im = 255 – im;
      im = 255 – cv2.erode(im, np.ones((3,3)), iterations=2)

      # Setup SimpleBlobDetector parameters.
      params = cv2.SimpleBlobDetector_Params()

      # Filter by Area.
      params.filterByArea = True
      params.minArea = 20

      params.filterByConvexity = False

      # Create a detector with the parameters
      ver = (cv2.__version__).split(‘.’)
      if int(ver[0]) < 3 :
      detector = cv2.SimpleBlobDetector(params)
      else :
      detector = cv2.SimpleBlobDetector_create(params)

      # Detect blobs.
      keypoints = detector.detect(im)

      # Draw blobs
      im_with_keypoints = cv2.drawKeypoints(im_orig, keypoints, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

      #Write image
      cv2.imwrite("treble_staff.jpg", im_with_keypoints)

      # Show blobs
      cv2.imshow("Keypoints", im_with_keypoints)
      cv2.waitKey(0)

    • You have to preprocess the image because the blobs are not isolated. Here is the code in python. The result is attached.

      ======================

      # Standard imports

      import cv2

      import numpy as np;

      # Read image

      im = cv2.imread(“blob.jpg”, cv2.IMREAD_GRAYSCALE)

      im_orig = im

      _, im = cv2.threshold(im, 128, 255, cv2.THRESH_BINARY)

      im = 255 – im;

      im = 255 – cv2.erode(im, np.ones((3,3)), iterations=2)

      # Setup SimpleBlobDetector parameters.

      params = cv2.SimpleBlobDetector_Params()

      # Filter by Area.

      params.filterByArea = True

      params.minArea = 20

      params.filterByConvexity = False

      # Create a detector with the parameters

      ver = (cv2.__version__).split(‘.’)

      if int(ver[0]) < 3 :

      detector = cv2.SimpleBlobDetector(params)

      else :

      detector = cv2.SimpleBlobDetector_create(params)

      # Detect blobs.

      keypoints = detector.detect(im)

      # Draw blobs

      im_with_keypoints = cv2.drawKeypoints(im_orig, keypoints, np.array([]), (0,255,0), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

      #Write image

      cv2.imwrite("treble_staff.jpg", im_with_keypoints)

      # Show blobs

      cv2.imshow("Keypoints", im_with_keypoints)

      cv2.waitKey(0)

  • vg

    Hi, Tried this code on an asymmetric data in pixel (a grayscale image of the metal edge) it gave me no results of blob. May i what are the params for an image of this kind?

    • Can you please post the image ?

      • vg

        Hi Satya,

        I am a beginner for opencv, see attached sample, normally image is in darker background as seen here, (forget the white border as this is an edited image).

        i tried following

        params.minThreshold = 10;
        params.maxThreshold = 100;

        // Filter by Area.
        params.filterByArea = true;
        params.minArea = 100;
        //params.maxArea = 1500;

        // Filter by Circularity
        params.filterByCircularity = true;
        params.minCircularity = 0.50;

        // Filter by Convexity
        params.filterByConvexity = true;
        params.minConvexity = 0.87;

        // Filter by Inertia
        params.filterByInertia = true;
        params.minInertiaRatio = 0.5;

        it did not help, with some other guess also 🙂

        Thanks in advance!

  • Achiles

    Hello, Mr. Satya Mallick, I used your code and acheived blob detection, thank you. Now, I am trying to find centroid (coordinates (x,y) of centre of blobs), so how I can do it?

    • Great. In the code you will notice the detector detects the keypoints and stores them in a vector named “keypoints”. Each keypoint has a member called pt that stores the centroid. In python you can print the centroids using the following code

      for kp in keypoints :
      print kp.pt

      Let me know if that helped.

      • Achiles

        Actually, I am writing code in C++, so tried to use member called _pt. However I could not extract centroid value or other characteristic as coordinates.

        • This should work. Right after the keypoints are detected using

          detector->detect( im, keypoints);

          Put these lines


          for
          (
          vector::iterator it = keypoints.begin();
          it != keypoints.end();
          ++it
          )
          {
          KeyPoint k = *it;
          cout << k.pt << endl;
          }

  • Emre Cimen

    Hello Mr. Mallick. Thank you for this tutorial. I had this problem in my code. Are there anyone had this problem?

    Undefined symbols for architecture x86_64:

    “cv::drawKeypoints(cv::Mat const&, std::__1::vector<cv::KeyPoint, std::__1::allocator > const&, cv::Mat&, cv::Scalar_ const&, int)”, referenced from:

    blobDetector(_IplImage*, CvRect) in main.o

    “cv::FeatureDetector::~FeatureDetector()”, referenced from:

    cv::SimpleBlobDetector::~SimpleBlobDetector() in main.o

    “cv::SimpleBlobDetector::Params::Params()”, referenced from:

    ___cxx_global_var_init in main.o

    “cv::SimpleBlobDetector::SimpleBlobDetector(cv::SimpleBlobDetector::Params const&)”, referenced from:

    ___cxx_global_var_init in main.o

    “cv::FeatureDetector::detect(cv::Mat const&, std::__1::vector<cv::KeyPoint, std::__1::allocator >&, cv::Mat const&) const”, referenced from:

    blobDetector(_IplImage*, CvRect) in main.o

    “VTT for cv::SimpleBlobDetector”, referenced from:

    cv::SimpleBlobDetector::~SimpleBlobDetector() in main.o

    ld: symbol(s) not found for architecture x86_64

    clang: error: linker command failed with exit code 1 (use -v to see invocation)

    • Looks like you are not linking to the incorrect library. Are you using OSX by any chance ?

      • Emre Cimen

        I’m using 10.9.5 version of OSX and 2.4.8 of OpenCV. I’m linking to core, highgui, improc and objdetect libraries.

        If libraries are correct, do you think changing the complier to LLVM GCC solve the problem? (I can not use this complier in new versions of Xcode).

        Thanks so much…

  • kevin

    Satya, thanks for the tutorial!

    Did you ever get the blob filter by color in this example working?

    • After looking at the code, I color example appears to be a bug. So it never worked for me.

  • Denny

    Hi, do you know how to detect the amount of objects that are connected? I’m able to detect them when they have space inbetween but when they are connected it doesn’t work and the program sees them as one object.

    • You can convert the image to binary and then use morphological operations to separate the circles. E.g. if your object is black and the background is white after you binarize the image, you can use morphological close ( i.e. dilation followed by erosion ) to separate the objects. Alternatively you can also count the object as two ( or more ) based on the area of the detected blob.

  • Shang Chieh Chou

    Hello Mr. Mallick

    I try to indicate the black blob in the image as below.

    but it can’t find out any one of blob.

    would you please help me to debug what happen? thanks.

    Image_SRoi=imread(“ROIImageGray.png”,IMREAD_GRAYSCALE);

    float thbilow = 40;

    float thbihigh = 120;

    params.minThreshold = thbilow;

    params.maxThreshold = thbihigh;

    params.filterByColor = true;

    params.blobColor=0;

    params.filterByArea=false;

    params.filterByCircularity=false;

    params.filterByInertia=false;

    params.filterByConvexity=false;

    Ptr detector = SimpleBlobDetector::create(params);

    detector->detect(Image_SRoi, keypoints);

    if (keypoints.size()>0)
    {
    for (int i=0;i<keypoints.size();i++)
    circle(Image_SRoi,cv::Point(keypoints[i].pt.x, keypoints[i].pt.y),3,cv::Scalar(255,255,255),1,8,0);
    // Show blobs
    imshow("keypoints", Image_SRoi );
    }
    else
    imshow("keypoints", Image_SRoi );
    }

  • mad

    hello Mr.Mallick,
    thank you for your tutorial , but i dont know why I have a problem with SimpleBlobDetector , whene i try to compile my project it displays ” undefined reference to symbol ‘_ZN2cv18SimpleBlobDetector6ParamsC1Ev'” , i dont know what i do ? i have added the library features2d

    • Looks like a linker error. Are you sure you are linking to the right library ( opencv_features2d ) ?

  • Dinn

    Thank you, Mr. Mallick. This was very helpful! However, I wanted to know if, after the detection of blobs – is it possible to access each blobs parameters( circularity, inertia, area etc…) ? If so, how?

  • Luke Bonnen

    The code runs when I use a picture of a petridish but it doesnt detect any blobs that it should. I tried to use a picture of some m&ms’ to detect those as blobs but I kept getting this error:

    File “C:UsersLuke.ipythonpython 27 codecell count”, line 7, in

    im_with_keypoints = cv2.drawKeypoints(im, keypoints, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

    error: ……..opencvmodulesfeatures2dsrcdraw.cpp:115: error: (-215) !outImage.empty() in function cv::drawKeypoints

    Any help would be awesome. I can’t seem to put my finger on the problem.

    • bhairav

      I too got the same error.

  • Lera Sinevich

    Thank you very much for a great tutorial. The question is: is it possible to get coordinates of the blobs’ centers? I am writing code in Python and I couldn’t find any information about what type “keypoints” is.
    I believe it is a python list, but I fail to iterate it.

    • Derek Janni

      use the dir(keypoints) command, built into python, to see what attributes keypoints has. use type(keypoints) to find its dtype.

  • John Spoerl

    Great guide,
    but I’m having a serious problem: when I attempt to use SimpleBlobDetector() I get a Attribute error: ‘module’ has no attribute ‘SimpleBlobDetector()’
    Do you have any insights to this? Could this be a problem with my installation of Opencv?

  • MURALI KRISHNA MURALI

    Hi Satya,

    I am trying to work with opencv using python your tutorials are always the best i can say.I am working on tracking people in video and assign each of them with particular number throughout the frame i am using camshift and kalman filter for tracking i am tracking based on the centroid of the blob(using findcontours funtion in opencv2) the problem i am facing is that i am unable to maintain the same ID no for same person throughout the video if there are more persons in video. What want to do is exactly like in picture in attachments any help is very useful to me.

    • Fabio

      I would like to do the same thing!

      • MURALI KRISHNA MURALI

        Any leads on this bro

      • Akın Evren Özsu

        search for connected components labeling

    • Bercebal

      Hi dude,
      I was wondering if you could guide me in how did you implement that program.
      I’ve to do the same as you but in c++.
      Greetings!

  • Shraddha

    Hello, I want to detect the white or bright blobs with black background, but the code is not working on my image that simply contains a white bob with black background. I set the parameter for color as:
    filterByColor = true;
    blobColor = 255;

    please let me know if I am missing something in my code apart from this parqameter setting and the code given as above.

  • MJ Woodward-Greene

    Shraddha, note the blog explains filter by color is broken. Try it without. any filter. With what sounds like a very simple image, this may work. You may also be able to use the find Contours instead.

  • Numlet

    Hello,
    I am using cv2 version 3.0.0. in python, when I try to do:

    detector = cv2.SimpleBlobDetector()

    the console is returning me:

    ‘module’ object has no attribute ‘SimpleBlobDetector’

    Has the function changed its name in this version?

    Thanks

    • MURALI KRISHNA MURALI

      Hi,
      you can try opencv version 2.4.11 it’s working for me note that these module names changes from version to version so you can find the same name version in opencv3

    • Ville Nummela

      Try

      detector = cv2.SimpleBlobDetector_create()

      The syntax has been changed in 3.0.0

  • Corey Kyle

    Is there a way to outline my blobs rather than fit a circle over them? When I return the radii and center parameters are they the metrics of the circle being drawn or of the blob itself(for example if my blob is slightly elliptical)?

  • Varun Goyal

    I want to detect leaf in captured image ,can you help me how I can do that?

  • Varun Goyal

    Here is the leaf that I want to detect. Looking Forward for help.

    • Shan

      If you mean the entire leaf, then you should try colour based thresholding like inRange() function and some edge detection. You should focus on imagesegmentation rather than blob detection.

      • masamune

        thats true

  • Static

    Ran your code above, got the following error:
    AttributeError: ‘module’ object has no attribute ‘drawKeypoints’
    Any ideas?

    • Static

      Fixed the problem: Had to upgrade to Jessie. Installed the latest OpenCV. Installed libgl1-mesa-dri. Now, everything works! Hope this helps someone.

  • satya

    Can anyone give the source for object detection in python+opencv plz help me

  • Alonso Castro

    Hi, I’m using C++ with a kinect and opencv to detect blobs and trigger a particle system. I was wondering if anyone have any idea of how to only track blobs in a particular location. I assume something like: if blobs are in an area less than 150 by 150 pixels then call draw particles. Just not sure where or how to make it happen. Please I would appreciate some help.

  • Shraddha

    Hi, in my program I have to use the center and radius of the blob detected. Could you please tell me how the detector is returning the center and radius of the blob. I have to actually draw a circle arround the blob which will be bigger in size than the blob’s size.

    • Shraddha

      I got the solution to this prob … 🙂

      • Arnab

        could you please share the solution, I too need to solve the same issue.

      • Ranjith Kumar Reddy

        Hello Shraddha & Arnab, can u share the solutions of yours.. even i am looking for the same

    • Gospel

      You figured this out and went so far as to post “I got the solution” but didn’t actually post the solution. I hate people like you so much.

      To get the X and Y position of your blob, you can use
      x = keypoints[i].pt[0]
      y = keypoints[i].pt[1]

      Where [i] is the current blob that you want to grab the centre of.

      Example:

      for i in range (0, len(keypoints)):

      x = keypoints[i].pt[0]
      y = keypoints[i].pt[1]
      print(x,y)

      Will run a for loop that grabs the centre point of each blob detected and then spits out a float value with the x and y to the console. If you want it to spit out an integer, use

      print(int(x),int(y))

      Then you can use the x,y values for other operations, like drawing a circle at the middle of each blob or using them to track movement.

      You can also just use print(len(keypoints)) to print the number of currently detected blobs.

      • Manu B.N

        What is the C++ equivalent for finding the centroid plz ?

        • Tweezy

          The centroid is a mathematical principle. That code above will work in C++.

  • Jonel Ho

    Hi, in my program I have to use the blob detection, but it seem that I can’t detect the blob in this music sheet. My goals is to detect the blob and write it into another image with only the blob with the color of black to each blob and get it’s centroid value and store it into an array or vector. Please help me I am still a student who really need help right now. Thank you in advance!

    • Shan

      Blob is just a collection of pixels, so what do you mean by blob in this image ? Even a straight line can be considered as a blob.

  • Dhwani Contractor

    Hii…I am writing this code but a garbage value is shown as size of the keypoint. Plz help me to debug me!!

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    using namespace std;

    using namespace cv;

    int main()

    {

    string wndNameGray = “Gray img”, wndNameOut = “Out”, filename = “D:\s.jpg”;

    Mat src, gray, thresh, binary;

    Mat out;

    namedWindow(“Source image”, WINDOW_FREERATIO);

    src = imread(filename);

    imshow(“Source image”, src);

    cvtColor(src, gray, COLOR_BGR2GRAY);

    namedWindow(“Gray image”, WINDOW_FREERATIO);

    imshow(“Gray image”, gray);

    vector keyPoints;

    //vector< vector > contours;

    //vector< vector > approxContours;

    SimpleBlobDetector::Params params;

    // Change thresholds

    params.minThreshold = 10;

    params.maxThreshold = 100;

    // Filter by Area.

    params.filterByArea = true;

    params.minArea = 10;

    params.maxArea = 100;

    //// Filter by Circularity

    //params.filterByCircularity = true;

    //params.minCircularity = 0.1;

    //// Filter by Convexity

    //params.filterByConvexity = true;

    //params.minConvexity = 0.87;

    //// Filter by Inertia

    //params.filterByInertia = true;

    //params.minInertiaRatio = 0.01;

    // Set up detector with params

    Ptr blobDetector = SimpleBlobDetector::create(params);

    blobDetector->detect(gray, keyPoints);

    size_t size = keyPoints.size();

    cout << "detected "<<size;

    Mat im_with_keypoints;

    drawKeypoints(gray, keyPoints, im_with_keypoints, Scalar(0, 255, 0), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

    // Show blobs

    imshow("keypoints", im_with_keypoints);

    waitKey(0);

    }

  • Sergio Iván

    Hello, thanks for your great post, your expertise on the software really shines.
    Is there a way to apply a mask to the SimpleBlobDetector? Using OpenCV 2 and Python2

    Thanks!

    • Hi Sergio,

      I don’t quite understand the question. Can you provide more details ? Please share an example ( using images preferably ).

      Thanks

  • David Gopinath

    Hello. For some reason, the function drawKeypoints does not seem to be found in the module. Has anyone else experienced this problem and/or has any suggestions to fix it?
    Thanks

    • Hi David,

      Please see the solution in the thread below. In the thread below a user (Static) had a similar problem and they solved it.

      “Fixed the problem: Had to upgrade to Jessie. Installed the latest OpenCV. Installed libgl1-mesa-dri. Now, everything works! Hope this helps someone.”

  • Siddharth

    hello, how do i detect blood in an image?

    • It is tough to say without looking at example images.

      • Siddharth

        Basically, I need to detect blood in any image, say in these two images, i just need to extract the part of blood only. Can you provide me an insight into doing this. thanks.

        • Try some color based segmentation. Try something simple first — convert image to HSV color space, and see if you can simply thresholds the channels to extract the blood region. Alternatively, you can build a simple gaussian model for the color of blood and use it to estimate the probability if a given color is blood-like.

        • Sebestyén Balázs

          I hope you are working on a parental control, or something like that, and you aren’t a serial killer… 🙂 I think blob detection and some color filtering is very insuficient for this task, but deep neural networks do the job.

  • Ramadhani ‘Rombane’ Pamapta Pu

    Greetings,

    Is there any way to COUNT how many blobs in a binary image, using C++?

    • In the above example keypoints.size() ( c++ ) or len(keypoints) ( python ) will give you the number of blobs.

      • Ramadhani ‘Rombane’ Pamapta Pu

        It is done. Thank you,sir.

      • Jack Kwakman

        Hello,
        I’m new in the field. Where do you place the keypoints.size() in the c++ code?

      • Manu B.N

        Sir how do I get the centroid of the blob in C++ ?

        • Reza Ghoddoosian

          did you find out how to get the centroid?

  • elkimp

    hello Mallick. Thanks for your great post about blob detection.
    but, could you tell me please how to make binary image from simpleblobdetector using C++?
    thanks for attention

  • Aoife O Sullivan

    The image shown is the difference between two images. I want to get the coordinates of the point where the blob is. I tried using your code above and changing the parameters, but I was not able to get it to find the blob. I think I need to understand better what effect changing the max and min thresholds.

    Any help in finding the coordinates of the blob would be appreciated.

  • Rohith Samineni

    Sir How do i change the shape of blob i.e i want a rectangular blob?

  • “it’s convex hull” -> “its convex hull”

  • Doron Fedida

    Hi,
    I “played” with the SimpleBlobDetector, based mainlly on this article (was the best in the web). Some dots:
    1) What is the default values of SimpleBlobDetector::Params ?

    2) Why simpleBlobDetector do not detect blobs in binarize images ?

    Thanks,
    Doron.

  • Don

    Hi,
    I “played” with the SimpleBlobDetector, based mainlly on this article (was the best in the web). Some dots:
    1) What is the default values of SimpleBlobDetector::Params ? I realize for example that the default value of ThresholdStep = 15.

    2) Why simpleBlobDetector do not detect blobs in binarize images ? (Images that already thresholded).

    Thanks,
    Don.

    • Peter Brookes-Smith

      Did you get an answer about blobs in binarised images?

  • Pedro Ferreira

    Is there a way to detect rectangular blobs and get their position, size and rotation?

  • kwh

    Thank you very much for posting all this work. I have a question about the blob detector. It has a way of imposing a variety of constraints on the blob features (inertia (eccentricity), circularity, etc). How can I get access to the computed values before the constraints are applied? I would like to see the distributions of these features for a large number of images. This would be very helpful for deciding what value to use for the constraints.

  • Paul Beck

    I am trying to use the detector with Swift. I am doing this by using an OpenCVWrapper C++. However, I am getting several error. I do not understand them as they implay that I am using stitching.hpp, but I am not. Any suggestions? I cannot figure out why it would be calling the stitching.hpp blenders and exposure compensate.

    The errors are: No member named ‘ExposureCompensator’ in namespace ‘cv::detail’ stitching.hpp
    and: No member named ‘Blender’ in namespace ‘cv::detail’ stitching.hpp

    Headers were added to the beginning as I was originally getting Parse Issues. For example, from the Expected Identifier NO in the macro. By adding these headers, I removed the Parse Issues as recommended in the source files, but this resulted in the new errors as above.

    #ifndef OPENCV_STITCHING_BLENDERS_HPP
    #define OPENCV_STITCHING_BLENDERS_HPP
    #if defined(NO)
    # warning Detected Apple ‘NO’ macro definition, it can cause build conflicts. Please, include this header before any Apple headers.
    #endif

    #ifndef OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP
    #define OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP
    #if defined(NO)
    # warning Detected Apple ‘NO’ macro definition, it can cause build conflicts. Please, include this header before any Apple headers.
    #endif

    #import “OpenWrapper.h”
    #import
    #import
    #import
    #import

    using namespace std;
    using namespace cv;
    @implementation OpenWrapper

    +(UIImage *) makeGrayscale:(UIImage *)myImage{

    // Convert UIImage to Mat
    Mat imageMat;
    UIImageToMat(myImage, imageMat);

    // Convert from color to grayscale image
    Mat graymat;
    cvtColor(imageMat, graymat, CV_BGR2GRAY);

    // Set up Simple Blob Parameters
    SimpleBlobDetector::Params params;

    params.minThreshold = 10;
    params.maxThreshold = 200;
    params.filterByArea = true;
    params.minArea = 1500;
    params.filterByCircularity = true;
    params.minConvexity = 0.87;
    params.filterByInertia = true;
    params.minInertiaRatio = 0.01;

    // Creat dectector with keypoints

    vector keypoints;
    Ptr detector = SimpleBlobDetector::create(params);
    detector->detect(graymat, keypoints);

    // Mat im_with_keypoints;
    Mat im_with_keypoints;

    drawKeypoints(graymat, keypoints, im_with_keypoints, Scalar(0,0,255), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

    // Show blobs
    imshow(“keypoints”, im_with_keypoints );
    waitKey(0);

    // Output results as UIIMage
    return MatToUIImage(graymat);

    }

    #endif
    #endif

    @end

  • Ben Kuebrich

    Using python. Is there a way to get the blob detector to return the borders of the blobs it’s detecting?

  • Walid Aly

    Thanks a lot
    I am doing vehicle counting, I finished now identifying the blobs using background subtraction.
    Is there is an intuitive way to get the i.d of the blob for tracking purposes and counting

    Walid

  • Rencita Dsouza

    Hi Mallick,
    can it be a rectangular blob detector instead of circular? If yes, what parameters i have to change?
    Thanks in advance

  • Vikas Tomar

    the doesn’t seem to work on python except for the given image

  • Khyati Thakker

    i do my project work on Buhler Z+ sortex machin. how can i detect differen colour of grain using opencv 3 and python27??/

  • Abin Abraham

    When I run the c++ code of blob detection in visual studio, it builds successfully but shows this error..
    “Unhandled exception at 0x000007FEFDC89E5D in vehicle1.exe: Microsoft C++ exception: cv::Exception at memory location 0x000000000028E630”..
    Can anybody help me to solve this?????

    • Sinan Akar

      One of your functions tries to use a null value. Check images I suggest.

  • Alejandro Quiñonez

    Hi, im trying to train a svm with the features that gave me the blob detector, but i dont know how to send de training data to the svm.

  • Atul Balaji

    The blobs detected are vey small. I am trying to perform thermal hotspot detction.
    The hotspots are not being found though I tried increasing minarea.

    • Saideep

      Hey, I’m working on same thermal hotspot detection and I’ve developed a system which is 95% accurate. I’m trying to develop it even better.

      Interested in working together?
      Email: saideeptalari@gmail.com

  • SadiaLakho

    hello. i need to apply this on videos rather than images. how can i do this? please help

  • Suraj Patil

    can you suggest some algorithm for calculating the count of blobs in video. i have used background image substraction and also detected the blobs but unable to find suitable algorithm for counting blobs..

    • Ozan Akyıldız

      len(keypoints) ?

      • Suraj Patil

        Used it but it counts object in a particular frame only. As the frame changes the count value also change. Want a solution so the count will remain intact till the end..

        • Ozan Akyıldız

          Well, don’t exactly know what you are going for but you can just keep adding the value.

          Are you talking about “number of unique blobs”? hen you have to parameterize each then compare them to see if it is a new blob. Distance of locations, color siez etc. would be factors to consider uniueness then.

  • Charan

    May i know how to do the same using .NET (C#) . Please let me know about it.
    Thanks in Advance.

  • Ashish Kumar

    i am taking out the blog of the square in which the i am using circularity parimeter in which it also detects square hexagonal circle i have checked the circularity by using following values 0.785 and 0.698 which is circularity of square and rectangle.

  • Peter So

    https://uploads.disquscdn.com/images/06bdbd6af71a30408d8f1ac5e067c064423bebdbce5a31e0b464e348ac750d33.jpg Hi thank you for the article. I am trying to understand the usage of the params and have generated another test image but I can’t get your blob.py program to detect my generated image even if I set all the params with wide acceptance criteria i.e. minArea = 1, minThreshold=0, maxThreshold=255. Any guidance would be very much appreciated!

  • Juan David Hernandez

    Hi, thanks for the article it was really useful for my. Now I’m trying to detect some eggs form this image but actually I just can detect a few of it. I’m using the following parameters for the Simple Blob Detector…

    params = cv2.SimpleBlobDetector_Params()
    # Change thresholds
    params.minThreshold = 240;
    params.maxThreshold = 256;
    #params.blobColor = 255
    # Filter by Area.
    params.filterByArea = True
    params.maxArea = 9000
    params.minArea = 500
    # Filter by Convexity
    params.filterByConvexity = True
    params.minConvexity = 0.9
    # Filter by Inertia
    params.filterByInertia = False
    params.maxInertiaRatio = 0.8
    params.minInertiaRatio = 0.2
    detector = cv2.SimpleBlobDetector_create(params)

    I need to detect all of it in order to count it. Any guidance would be very much appreciated!
    Thanks.
    https://uploads.disquscdn.com/images/25f106d152731b8ba4b4ccd14ca95e89198b4749cb74f85147a1920402063ee1.jpg

  • Dago

    Hi everyone. I need to draw random blobs filled with specific color. Does anyone have done that before?