在位图中查找斑点

Find blobs in bitmap

我使用AForge.Net在位图中查找斑点,我的位图如下:

我的问题是 AForge.Net 只检测到一个斑点,而实际上在一条细线上有两个相连的斑点。

我的问题是有没有一种算法可以识别出两个大的 blob,它们之间的连接很薄?以及我如何在 C# 或 VB?

中实现此算法

示例图片:

一个快速的解决方案是应用开运算符 http://www.aforgenet.com/framework/features/morphology_filters.html

如果预先知道线条的最大粗细,可以多次应用腐蚀算子,然后应用相同次数的膨胀算子,从而有效地去除细线。但是,这将改变 2 个斑点的形状。

如果需要更复杂的东西,您可能需要遵循本文中的方法,它将距离变换与分水岭算法相结合: https://docs.opencv.org/3.1.0/d3/db4/tutorial_py_watershed.html

  1. 尝试腐蚀 Class ,它可以清除中心的细线。

http://www.aforgenet.com/framework/docs/html/90a69d73-0e5a-3e27-cc52-5864f542b53e.htm

  1. 调用Dilatation Class,得到原始尺寸,

http://www.aforgenet.com/framework/docs/html/88f713d4-a469-30d2-dc57-5ceb33210723.htm

  1. 再次找到 blob,你就会找到它。

也许您想在您的项目中使用 OpenCV。它更容易和更快。

努格特: https://www.nuget.org/packages/OpenCvSharp3-AnyCPU/3.3.1.20171117

Mat im = Cv2.ImRead("blob.jpg", ImreadModes.GrayScale);
SimpleBlobDetector detector = SimpleBlobDetector.Create();
KeyPoint[] points = detector.Detect(im);
Mat result = new Mat();
Cv2.DrawKeypoints(im, points, result, Scalar.Red); 

正如其他人所建议的,我会使用 OpenCv 而不是 AForge(似乎 AForge 已经有一段时间没有更新了,而且 OpenCv 有很多可用的样本)。 对于 C#,我建议使用 OpenCvSharp nuget 包。它很容易使用,因为代码真的看起来像 C++ 或 python 代码,就像大多数示例一样。

所以,OpenCv 有一个 blob 检测器,但它检测的是 blob 中心,所以在你的情况下,你似乎更关注 contours 而不是 blob(通常是这种情况).

幸运的是,使用 OpenCv 和您的示例图像,它可以正常工作 w/o 做任何花哨的事情(我们甚至不必先腐蚀图像),我们可以只使用 findContours,过滤一些毛刺,然后得到凸包。这是一个示例代码,演示了:

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();
        }
    }
}