在位图中查找斑点
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
- 尝试腐蚀 Class ,它可以清除中心的细线。
http://www.aforgenet.com/framework/docs/html/90a69d73-0e5a-3e27-cc52-5864f542b53e.htm
- 调用Dilatation Class,得到原始尺寸,
http://www.aforgenet.com/framework/docs/html/88f713d4-a469-30d2-dc57-5ceb33210723.htm
- 再次找到 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();
}
}
}
我使用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
- 尝试腐蚀 Class ,它可以清除中心的细线。
http://www.aforgenet.com/framework/docs/html/90a69d73-0e5a-3e27-cc52-5864f542b53e.htm
- 调用Dilatation Class,得到原始尺寸,
http://www.aforgenet.com/framework/docs/html/88f713d4-a469-30d2-dc57-5ceb33210723.htm
- 再次找到 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();
}
}
}