Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find blobs in bitmap

I use AForge.Net for find blobs in bitmap, my bitmap is as follows:

Search for blobs in AForge.Net

My problem is that AForge.Net detects only one blob when in fact there are two connected blobs on a thin line.

My question is there an algorithm that identifies that there are two large blobs with thin connection between them? And how I implement this algorithm in C# or VB?

Image for samples:

Image for samples

like image 311
google dev Avatar asked Jan 11 '18 19:01

google dev


2 Answers

As others suggested, I would use OpenCv instead of AForge (it seems AForge has not been updated for a while plus OpenCv has lots of samples available). With C#, I suggest the OpenCvSharp nuget package. It's easy to use because the code really looks like C++ or python code, like most samples.

So, OpenCv has a blob detector, but it detects blob centers, so in your case, it seems you're more after contours than blobs (which is often the case).

Luckily, with OpenCv and your sample image, it just works w/o doing anything fancy (we don't even have to erode the image first), we can just use findContours, filter some glitches, and get the convexHull. Here is a sample code that demonstrates that:

using (var src = new Mat(filePath))
using (var gray = new Mat())
{
    using (var bw = src.CvtColor(ColorConversionCodes.BGR2GRAY)) // convert to grayscale
    {
        // invert b&w (specific to your white on black image)
        Cv2.BitwiseNot(bw, gray);
    }

    // find all contours
    var contours = gray.FindContoursAsArray(RetrievalModes.List, ContourApproximationModes.ApproxSimple);
    using (var dst = src.Clone())
    {
        foreach (var contour in contours)
        {
            // filter small contours by their area
            var area = Cv2.ContourArea(contour);
            if (area < 15 * 15) // a rect of 15x15, or whatever you see fit
                continue;

            // also filter the whole image contour (by 1% close to the real area), there may be smarter ways...
            if (Math.Abs((area - (src.Width * src.Height)) / area) < 0.01f)
                continue;

            var hull = Cv2.ConvexHull(contour);
            Cv2.Polylines(dst, new[] { hull }, true, Scalar.Red, 2);
        }

        using (new Window("src image", src))
        using (new Window("dst image", dst))
        {
            Cv2.WaitKey();
        }
    }
}

enter image description here

like image 63
Simon Mourier Avatar answered Oct 21 '22 06:10

Simon Mourier


One quick solution would be to apply the opening operator http://www.aforgenet.com/framework/features/morphology_filters.html

If the maximum thickness of the line is known in advance, one could apply the erosion operator multiple times and then apply the dilation operator the same number of times, effectively removing the thin line. This will change the shape of the 2 blobs, however.

If something more sophisticated is required, you might want to follow the approach in this, which combines the distance transform with the watershed algorithm: https://docs.opencv.org/3.1.0/d3/db4/tutorial_py_watershed.html

like image 40
robot_chef Avatar answered Oct 21 '22 07:10

robot_chef