Improved blob detection

Hi, I’m not sure where to ask this so if this is the wrong place please point me to the correct one.

But anyways, the OpenCV blob detection in python is extremely frustrating to me because it is nearly useless for the task I need it for and it could be massively improved.

I’m working with images that typically have 4 blobs that I need to detect, but occasionally the images have 5+ blobs and in this case I need to filter out the blobs, but this isn’t really possible with the openCV blob detector because it gives no information besides area and blob center, but the funny thing is the blob detector has the ability to calculate a lot of useful values for determining which 4 blobs are the “best” blobs but those values are inaccessible to the python user because you can only pass parameters to the blob detector that then filters out the blobs before hand but it never returns the useful values so I can filter them out by hand.

To better explain what I mean lets take a concrete example I have 5 blobs in my image with the following circularities: [0.99, 0.89, 0.80, 0.79, 0.75] and I want to get the blobs with the highest circularity. So my only way to do this with the current blob detector is to do it with some kind of brute force like in this pseudocode

blobs = detect(img, min_circularity=0.5) # 5 blobs detected
blobs = detect(img, min_circularity=0.6) # 5 blobs detected
blobs = detect(img, min_circularity=0.7) # 5 blobs detected
blobs = detect(img, min_circularity=0.8) # 3 blobs detected
blobs = detect(img, min_circularity=0.75) # 5 blobs detected
blobs = detect(img, min_circularity=0.77) # 4 blobs detected like we wanted

So we need multiple passes over the image when it could be solved in a single pass if the detector was implemented slightly differently like in the following way:

blobs = detect(img)
blobs = sorted(blobs, key = lambda blob: blobl.circularity)[:4]

I know that matlab does it in a similar way to how I want, but I’d rather not use matlab for anything. Where do I go/what do I do to get this implemented in OpenCV?

please show such a picture.

yes the simple blob detector is old code and very closed down.

the resulting Keypoint objects don’t have attributes to hold these values.

you could change OpenCV source to reveal these attributes however.

or you could use connected components with stats (very basic stats) or findContours, and manually calculate those attributes.

blobs

Here is one such Image, I’d like to eliminate the center bottom blob, it seems that the findContours function might be good enough for what I need, thanks for that. But I still wonder if there shouldn’t be a better blob detector in open cv because I’m not the only one who has run into this problem: python - opencv simpleblobdetector - get blob attributes for identified blobs - Stack Overflow

things happen when someone bothers to write the code for it :wink:

I thought about doing it but I don’t really know where to start. I guess I can’t just overwrite the existing blob detector because other people depend on it so I have to make a new one. Do I just clone the openCV C++ repo implement a class and then make a pull request? Where do I then go to make python bindings for the python version?

yeah that’s the curse of “APIs”. someone once in pre-history figured “I’ll write this code and put it in the library!” and now everyone’s stuck with it.

some stuff, when it becomes disused or something clearly better comes along, gets deprecated or moved off into contrib. there is room for evolution. OpenCV 5 has specific “Evolution” proposals, e.g. for a revised highgui module.

I absolutely understand and see a use in getting those metrics. the code exists to calculate them. they shouldn’t be hidden behind a mere filter.

perhaps hop on over to Issues · opencv/opencv · GitHub, state your desire to get those metrics, ask for a discussion on how that could be implemented.

I think the most likely outcome is a new API call. those are always possible, they don’t require changing any existing API.

the SimpleBlobDetector only is a class/object because it carries a bunch of state that only affects the filtering. the calculation of metrics is completely stateless. a function would be perfectly fine for that.

it’d only require moving part of the existing code into that new API, and it’ll be used in the SimpleBlobDetector, which then does its filtering as usual, and anyone that only needs the metrics calls the new API.

I could be wrong. maybe a new method to SimpleBlobDetector, which returns something other than Keypoints, would be more suitable. that would allow people to combine getting the metrics with getting them filtered optionally.

the connectedComponentsWithStats returns a Mat where each column represents one metric (there’s an enum to name those columns). or maybe a new object will be introduced, analogous to Keypoint, but with the right member variables.

you can definitely make pull requests. however for more complex stuff it’s a good idea to open an issue and have a discussion first, so you know what direction to go in. you want to be in agreement with a few of the core devs, which decide if the pull request gets accepted/merged or not. they are reasonable people and what I’ve seen of their advice has been good.

python bindings happen automagically. you just need to make sure the function signature ticks a few boxes, e.g. doesn’t just take “cv::Mat” but says “InputArray”, and there’s a CV_EXPORTS_W or somesuch. OpenCV: How OpenCV-Python Bindings Works?

this kind of “detailed” advice you’d get from the discussion of an issue, from the core devs.

1 Like