问题
I have many images consisting of circles(varying from 1 to 4) in each image. I am trying to get a clear circle images by filling the missed pixels along the circle path.
I have tried Hough-transform, but its parameters are image specific: for each image I have to change the parameters. With this problem I am unable keep them in a single for loop.
Please provide some method to do it. Thanks
回答1:
imfindcircles Does not work
The most "natural" way to approach this problem is to use Matlab's imfindcircles. However, that function assume the circles in the image are "full", yet in your examples you only have the (incomplete) boundaries of the circles, thus imfindcircles
cannot be directly applied to your data.
Alternative Approach
You can use ransac to fit circles to your data. Fit one circle at a time to as many points as you can, terminate when there are too few points left that fit no circle at all.
To use RanSac you basically need to implement two methods:
Model fitting method,
fitFcn
, Given a small sample of your points - fit a circle to them.Distance to model method,
distFcn
, Given a circle ("model") find the distance of each point to that circle.
Once you have these two methods, RanSac operates roughly like:
- randomly sample very few points
- use fitFcn
to fit a circle to these sampled points
- use distFcn
to compute the distance of all points to estimated circle
- if enough points are close to the circle, accept this circle and remove all point that "belongs" to that circle
- terminate if no circle was found or not enough "unexplained" points
This can be easily implemented in Matlab.
First consider fitFcn
: we need a function that compute (cx
, cy
, r
) - the three parameters of a 2D circle (center and radii). Given a point (x
, y
) it fits a circle iff
(x - cx)^2 + (y - cy)^2 = r^2
We can write this equation as a linear relation between known points (x
, y
) and unknown circle (cx
, cy
, r
) in the following manner
[-2*x, -2*y, 1] [ cx ;
cy ; = [-x^2-y^2]
cx^2 + cy^2 - r^2 ]
Using a least squares estimation (in a similar manner as in this answer), we can recover the circle parameters given enough points (at least 3) on the circle
This is how the code actually looks like
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)
Now that we can fit a circle to points, we need to compute the distance using distFcn
that is quite simple
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));
Putting it all together with matlab's 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{:});
And the output of this function on your data is (using viscircles to plot the circles):
来源:https://stackoverflow.com/questions/56846801/fill-the-circular-paths-in-image