我在每个图像中都有很多由圆圈组成的图像(从1变到4)。我试图通过沿圆路径填充丢失的像素来获得清晰的圆图像。
我尝试了霍夫变换,但是它的参数是特定于图像的:对于每个图像,我都必须更改参数。由于这个问题,我无法将它们放在单个for循环中。
答案 0 :(得分:4)
imfindcircles
不起作用
解决此问题的最“自然”方式是使用Matlab的imfindcircles
。但是,该函数假定图像中的圆圈是“完整的”,但是在您的示例中,您仅具有圆圈的(不完整)边界,因此imfindcircles
无法直接应用于您的数据。
替代方法
您可以使用ransac
使圆圈适合数据。一次拟合一个圆至尽可能多的点,当剩下的点太少而根本不适合圆时终止。
要使用RanSac,您基本上需要实现两种方法:
模型拟合方法,fitFcn
,假设您的点数很小,请在其上画一个圆。
距模型方法的距离,distFcn
,在给定一个圆(“模型”)的情况下,找到每个点到该圆的距离。
一旦有了这两种方法,RanSac的运行方式大致如下:
-随机采样很少的点
-使用fitFcn
使圆适合这些采样点
-使用distFcn
计算所有点到估计圆的距离
-如果有足够的点靠近该圆,则接受该圆并删除所有“属于”该圆的点
-如果找不到圆圈或“无法解释的”点不足
这可以在Matlab中轻松实现。
首先考虑 fitFcn
:我们需要一个计算(cx
,cy
,r
)-2D的三个参数的函数圆(中心和半径)。给定一个点(x
,y
),该点适合圆iff
(x - cx)^2 + (y - cy)^2 = r^2
我们可以将该方程写为已知点(x
,y
)和未知圆(cx
,cy
,r
)之间的线性关系以以下方式
[-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
绘制圆):