填充图像中的圆形路径
Fill the circular paths in image
我有很多图像,每张图像中都有圆圈(从 1 到 4 不等)。我试图通过沿着圆形路径填充丢失的像素来获得清晰的圆形图像。
我试过霍夫变换,但它的参数是特定于图像的:对于每张图像我都必须更改参数。有了这个问题,我无法将它们保持在一个 for 循环中。
请提供一些方法来做到这一点。谢谢
imfindcircles
无效
解决此问题的最 "natural" 方法是使用 Matlab 的 imfindcircles
。但是,该函数假设图像中的圆圈是 "full",但在您的示例中,您只有圆圈的(不完整)边界,因此 imfindcircles
不能直接应用于您的数据。
替代方法
您可以使用 ransac
使圆适合您的数据。一次将一个圆拟合到尽可能多的点,当剩下的点太少根本无法拟合圆时终止。
要使用RanSac,您基本上需要实现两个方法:
模型拟合方法,fitFcn
,给定你的点的小样本 - 拟合一个圆圈。
距离模型方法,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
绘制圆圈):
我有很多图像,每张图像中都有圆圈(从 1 到 4 不等)。我试图通过沿着圆形路径填充丢失的像素来获得清晰的圆形图像。
我试过霍夫变换,但它的参数是特定于图像的:对于每张图像我都必须更改参数。有了这个问题,我无法将它们保持在一个 for 循环中。
请提供一些方法来做到这一点。谢谢
imfindcircles
无效
解决此问题的最 "natural" 方法是使用 Matlab 的 imfindcircles
。但是,该函数假设图像中的圆圈是 "full",但在您的示例中,您只有圆圈的(不完整)边界,因此 imfindcircles
不能直接应用于您的数据。
替代方法
您可以使用 ransac
使圆适合您的数据。一次将一个圆拟合到尽可能多的点,当剩下的点太少根本无法拟合圆时终止。
要使用RanSac,您基本上需要实现两个方法:
模型拟合方法,
fitFcn
,给定你的点的小样本 - 拟合一个圆圈。距离模型方法,
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
绘制圆圈):