填充图像中的圆形路径

Fill the circular paths in image

我有很多图像,每张图像中都有圆圈(从 1 到 4 不等)。我试图通过沿着圆形路径填充丢失的像素来获得清晰的圆形图像。

我试过霍夫变换,但它的参数是特定于图像的:对于每张图像我都必须更改参数。有了这个问题,我无法将它们保持在一个 for 循环中。

请提供一些方法来做到这一点。谢谢

imfindcircles 无效
解决此问题的最 "natural" 方法是使用 Matlab 的 imfindcircles。但是,该函数假设图像中的圆圈是 "full",但在您的示例中,您只有圆圈的(不完整)边界,因此 imfindcircles 不能直接应用于您的数据。

替代方法
您可以使用 ransac 使圆适合您的数据。一次将一个圆拟合到尽可能多的点,当剩下的点太少根本无法拟合圆时终止。

要使用RanSac,您基本上需要实现两个方法:

  1. 模型拟合方法fitFcn,给定你的点的小样本 - 拟合一个圆圈。

  2. 距离模型方法,distFcn,给定一个圆("model")求每个点到那个圆的距离.

有了这两种方法后,RanSac 的操作大致如下:
- 随机抽取很少的点
- 使用 fitFcn 将圆拟合到这些采样点
- 使用 distFcn 计算所有点到估计圆的距离
- 如果有足够多的点靠近圆圈,接受这个圆圈并移除所有 "belongs" 到那个圆圈
的点 - 如果没有找到圆或没有足够的 "unexplained" 点

则终止

这可以在 Matlab 中轻松实现。

首先考虑fitFcn:我们需要一个函数来计算(cx, cy, r) -二维圆的三个参数(圆心和半径)。给定一个点 (x, y) 它适合一个圆 iff

(x - cx)^2 + (y - cy)^2 = r^2

我们可以把这个方程写成已知点(x,y)和未知圆(cx,cy,[=26=之间的线性关系]) 以下方式

[-2*x, -2*y, 1] [ cx ; 
                  cy ;                 = [-x^2-y^2]
                  cx^2 + cy^2 - r^2 ]

使用最小二乘估计(与 this answer 中类似的方式),我们可以在给定圆上足够多的点(至少 3 个)的情况下恢复圆参数

代码实际上是这样的

function crc = fit_circle(xy)  % xy is n-by-2 matrix of point coordinates
% fit in least squares sens
x = xy(:, 1);
y = xy(:, 2);
X = [-2*x, -2*y, ones(size(x))]; 
Y = -x.^2 - y.^2;
crc = (X\Y).';  % least squares solution
r2 = -crc(3) +crc(1).^2 + crc(2).^2; 
if r2 <= 0
    crc(3) = 0;
else    
    crc(3) = sqrt(r2);
end
% output crc is a 3 vector (cx, cy, r)

现在我们可以用一个圆来拟合点,我们需要使用distFcn来计算距离,这很简单

function dst = distFcn(crc, xy)
% how good a fit circle for points
x = xy(:, 1) - crc(1);
y = xy(:, 2) - crc(2);
dst = abs(sqrt(x.^2 + y.^2) - crc(3));

将它们与 matlab 的 ransac:

放在一起
function circles = find_circles(bw)
% parameters
sample_size = 4;
max_distance = 10;
min_num_points_in_circle = 50;

[y, x] = find(bw > max(bw(:))/2);  % all edges in the image

circles = {};
counter = 0;
while numel(x) > 10 * sample_size && counter < 10
    try
        [circle, inlierIdx] = ransac([x, y], @fit_circle, @distFcn, ...
            sample_size, max_distance);
    catch
        break
    end
    % refit using only inliers
    circle = fit_circle([x(inlierIdx) y(inlierIdx)]);
    dst = distFcn(circle, [x y]);
    founfit = dst < max_distance;
    if sum(founfit) > min_num_points_in_circle
        % this model fits enough points
        circles{end+1} = circle;
        x(founfit) = [];
        y(founfit) = [];
    else
        counter = counter + 1;
    end    
end
circles = vertcat(circles{:});

此函数对您的数据的输出是(使用 viscircles 绘制圆圈):