【问题标题】:Generating a segmentation mask for circular particles from threshold mask?从阈值蒙版生成圆形粒子的分割蒙版?
【发布时间】:2020-11-06 19:27:03
【问题描述】:

我正在尝试在所附图像中找到所有圆形粒子。这是我唯一拥有的图片(连同它的反面)

我已阅读this post,但我无法使用 hsv 值进行阈值处理。我尝试过使用霍夫变换。

circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, dp=0.01, minDist=0.1, param1=10, param2=5, minRadius=3,maxRadius=6)

并使用以下代码进行绘图

names =[circles]
for nums in names:
  color_img = cv2.imread(path)
  blue = (211,211,211)
  for x, y, r in nums[0]:
    cv2.circle(color_img, (x,y), r, blue, 1)
    
  plt.figure(figsize=(15,15))
  plt.title("Hough")
  plt.imshow(color_img, cmap='gray')

以下代码用于绘制掩码:

for masks in names:
  black = np.zeros(img_gray.shape)
  for x, y, r in masks[0]:
    cv2.circle(black, (x,y), int(r), 255, -1)  # -1 to draw filled circles
plt.imshow(black, gray)
  

然而,我只能得到以下面具,如果相当差的话。

这是一张关于什么被认为是粒子和什么不是粒子的图像。

【问题讨论】:

  • 使用 cv2.contourArea 的简单轮廓区域过滤应该可以工作

标签: python python-3.x opencv image-processing computer-vision


【解决方案1】:

我的方法基于一个简单的观察,即图像中的大多数粒子的周长大致相同,而“非粒子”的周长比它们大。

首先,看一下 RANSAC 算法以及它如何找到内点和异常点。它基本上适用于 2D 数据,但在我们的案例中我们必须将其转换为 1D 数据。

在你的情况下,我称正确粒子的内点和不正确粒子的异常值。

我们必须处理的数据将是这些粒子的周长。要获取周长,请在此图像中找到轮廓并获取每个轮廓的周长。 Refer this for information about Contours.

现在我们有了关于 RANSAC 算法的数据、知识和我们上面提到的简单观察。现在在这个数据中,我们必须找到最密集和最紧凑的集群,它将包含所有的内点,而其他的将是异常点。

现在让我们假设内点在 40-60 的范围内,并且离群值超出 60。让我们定义一个阈值 T = 0。我们说对于数据中的每个点,该点的内点都在范围内of(该点的值 - T,该点的值 + T)。

现在首先遍历数据中的所有点并计算 T 的点的内点数并存储此信息。找到 T 值可能的最大内点数。现在将 T 的值增加 1,然后再次找到该 T 可能的最大内点数。通过将 T 的值一个一个地递增来重复这些步骤。

T 的值范围内的最大内点数是相同的。这些内点是图像中的粒子,周长大于这些内点的粒子是异常值,因此是图像中的“非粒子”。

我已经在我的测试用例中尝试过这个算法,它与你的相似并且有效。我总是能够确定异常值。我希望它也对你有用。

最后一件事,我发现你的粒子边界不规则且不平滑,如果在这张图片中这对你不起作用,请尝试使它们平滑并使用此算法。

【讨论】:

    【解决方案2】:

    一种简单的方法是稍微腐蚀图像,分离接触的圆形物体,然后进行连通分量分析并丢弃所有大于某个选定阈值的物体,最后将图像放大,使圆形物体近似于原始大小再次。我们可以对标记的图像进行这种膨胀,这样您就可以保留分离的对象。

    我使用DIPlib 是因为我最熟悉它(我是作者)。

    import diplib as dip
    
    a = dip.ImageRead('6O0Oe.png')
    a = a(0) > 127        # the PNG is a color image, but OP's image is binary,
                          # so we binarize here to simulate OP's condition.
    
    separation = 7        # tweak these two parameters as necessary
    size_threshold = 500
    
    b = dip.Erosion(a, dip.SE(separation))
    b = dip.Label(b, maxSize=size_threshold)
    b = dip.Dilation(b, dip.SE(separation))
    

    请注意,我们在这里使用的图像似乎是放大的屏幕截图,而不是 OP 正在处理的原始图像。如果是这样,则必须使参数更小以识别较小图像中的较小对象。

    【讨论】:

    • 尝试运行代码时出现以下错误 RuntimeError: Reading JavaIO file: cannot find interface class (is it supported?) in function: dip::FileInformation dip::javaio::ImageReadJavaIO( dip::Image&, const String&, const String&) (/diplib/javaio/src/javaio.cpp 在第 124 行) 在函数中: dip::FileInformation dip::ImageRead(dip::Image&, const String&, dip::字符串)(/diplib/include/diplib/simple_file_io.h 第 91 行)
    • @john:您需要安装 Bio-Formats 才能读取 PNG 文件:python -m diplib download_bioformats(如此处所述:pypi.org/project/diplib/3.0b5——我们也需要在其他地方包含该信息,我明白了) .或者,使用 OpenCV 或任何其他工具读取图像。如果它是一个 NumPy 数组,你就可以开始了。
    • 谢谢!另外我如何显示与您相同的图像。当我使用 plt.imshow(b) 时,图像看起来完全不同。
    • @john: dip.viewer.Show(b),然后点击右上角的“标签”按钮。这提供了一个交互式工具来检查图像。或者使用 pyplot 显示 dip.Show(b,'labels')
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 1970-01-01
    • 1970-01-01
    • 2021-03-03
    • 2014-10-15
    • 1970-01-01
    • 2014-03-27
    相关资源
    最近更新 更多