填充图像中的圆形路径

时间:2019-07-02 06:48:42

标签: python-3.x matlab image-processing image-segmentation edge-detection

我在每个图像中都有很多由圆圈组成的图像(从1变到4)。我试图通过沿圆路径填充丢失的像素来获得清晰的圆图像。

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

请提供一些方法。谢谢1. contains one circles

2. contains two circles

3. contains three circles

4. contains four circles

1 个答案:

答案 0 :(得分:4)

imfindcircles不起作用
解决此问题的最“自然”方式是使用Matlab的imfindcircles。但是,该函数假定图像中的圆圈是“完整的”,但是在您的示例中,您仅具有圆圈的(不完整)边界,因此imfindcircles无法直接应用于您的数据。

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

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

  1. 模型拟合方法fitFcn,假设您的点数很小,请在其上画一个圆。

  2. 距模型方法的距离distFcn,在给定一个圆(“模型”)的情况下,找到每个点到该圆的距离。

一旦有了这两种方法,RanSac的运行方式大致如下:
-随机采样很少的点
-使用fitFcn使圆适合这些采样点
-使用distFcn计算所有点到估计圆的距离
-如果有足够的点靠近该圆,则接受该圆并删除所有“属于”该圆的点
-如果找不到圆圈或“无法解释的”点不足

这可以在Matlab中轻松实现。

首先考虑 fitFcn :我们需要一个计算(cxcyr)-2D的三个参数的函数圆(中心和半径)。给定一个点(xy),该点适合圆iff

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

我们可以将该方程写为已知点(xy)和未知圆(cxcyr)之间的线性关系以以下方式

[-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绘制圆):
enter image description here enter image description here enter image description here enter image description here