圆内点与圆拟合

问题描述 投票:0回答:1

我有一个嘈杂的二值化图像,其中大多数白点位于一个圆圈内。什么是拟合圆的好算法?该算法应该具有鲁棒性,能够处理圆圈中的各种缺陷。

这是一个示例图像:

Example Image

以下是我迄今为止尝试过的一些方法:

  1. 霍夫圆:不够鲁棒;
  2. 扩张,找到凸包并将凸包拟合成一个圆:不够鲁棒;
  3. 几种常规的圆拟合算法 - 它们只能拟合圆周上的点,不知道如何处理圆内的点。
  4. 计算两两白点的距离,将它们放入直方图中,并使用 otsu 找到与圆的直径相匹配的“阈值”。太慢了,有几万个点。

编辑:在此处附加原始图像:

Original Image

我对原始图像做了什么以获得上述二值图像:

  • 将其设为灰度;
  • 找到并去除太暗的像素(主要是两条黑色曲线,不可以作为圆的提示来检测),将其替换为图像的灰度中值;
  • 使用 Otsu 阈值进行二值化(反转)
  • 填充孔洞 - 在此图像上并不重要,但对于圆圈内内容较密集的图像,它有很大帮助
computer-vision feature-detection
1个回答
0
投票

这就是我的方法。最初的结果不是很好,还需要更多的工作。我将在最后详细说明后续步骤。

第1步:创建蒙版并准备图像

遮罩标识了粗黑圆圈内的区域,我猜这是容器。我们希望确保除此之外的任何事情都不会影响我们的结果。

import diplib as dip

# OP's original color image
img = dip.ImageRead("zDNIxW5n.jpg")
# We use the red channel, color information is not important and red has the best contrast
img = img(0)

# Find mask for analysis area by detecting the black circle (large dark areas)
approximate_radius = 400
circle = dip.AreaClosing(img, filterSize=10000)
gv = dip.Gradient(circle, 3)
circle = dip.OtsuThreshold(dip.Norm(gv))
x = dip.FindHoughCircles(circle, gv, range=[approximate_radius-100, approximate_radius+100], distance=100, fraction=0.9)
center = x[0][:2]
radius = x[0][2] - 20  # offset radius to ensure we clear out everything
mask = dip.DistanceToPoint(img.Sizes(), center, distance="square") < radius**2

# Prepare image
img = dip.Percentile(img, mask, percentile=95) - img
img.Mask(mask)

在帖子底部,您可以看到

img
现在的样子。

第 2 步:初步估计圆心

# Find centroid
center = dip.CenterOfMass(img)

这个中心并不精确,因为圆内的物质分布不均匀,而且圆外也有一些信号。

第 3 步:初步估计圆的半径

为此,我们根据到上面找到的质心的距离创建图像的总投影。

# Find radius, as the first point where the sum projection gets to half its maximum
proj = dip.RadialSum(img, center=center)
max_pos = dip.PositionMaximum(proj)[0][0]
max_val = proj[max_pos][0]
x = (proj < max_val / 2) & (dip.CreateXCoordinate(proj.Sizes(), mode={"corner"}) > max_pos)
radius = dip.PositionMaximum(x, mode="first")[0][0]

proj
函数如下所示: the projection

随着到中心的距离增加,总和也增加。在圆圈之外,灰度值很少的地方,总和应该接近 0。

我们将最大值之后的点作为半径,该点的总和达到最大值的一半。

因为我们的初始中心不是实际的中心,所以此时的向下坡度并不是很陡。如果我们找到实际的中心,那么坡度会非常陡。

因此,此时我们可以进行迭代细化,即移动质心以使斜率尽可能陡。这涉及重复计算步骤 3,并评估

proj
max_pos
的陡度(例如,通过比较
max_pos - 2
max_pos + 2
处的值,或通过
max_pos
周围的几个点拟合一条直线)。

初始中心和半径如下所示:

import matplotlib as mpl
import matplotlib.pyplot as plt

img.Show()
c = mpl.patches.Circle(center, radius=radius, fill=False, edgecolor='r')
plt.gca().add_patch(c)
plt.show()

cleaned-up image with circle overlaid


PS:我在 Python 中使用 DIPlib 来进行此演示。我是 DIPlib 的作者..

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.