Fitting largest circle in free area in image with distributed particle

后端 未结 5 548
無奈伤痛
無奈伤痛 2020-12-07 16:49

I am working on images to detect and fit the largest possible circle in any of the free areas of an image containing distributed particles:

5条回答
  •  没有蜡笔的小新
    2020-12-07 17:02

    I'd like to propose another solution based on a grid search with refinement. It's not as advanced as Ander's or as short as rahnema1's, but it should be very easy to follow and understand. Also, it runs quite fast.

    The algorithm contains several stages:

    1. We generate an evenly-spaced grid.
    2. We find the minimal distances of points in the grid to all provided points.
    3. We discard all points whose distances are below a certain percentile (e.g. 95th).
    4. We choose the region which contains the largest distance (this should contain the correct center if my initial grid is fine enough).
    5. We create a new meshgrid around the chosen region and find distances again (this part is clearly sub-optimal, because the distances are computed to all points, including far and irrelevant ones).
    6. We iterate the refinement within the region, while keeping an eye on the variance of the top 5% of values -> if it drops below some preset threshold we break.

    Several notes:

    • I have made the assumption that circles cannot go beyond the scattered points' extent (i.e. the bounding square of the scatter acts as an "invisible wall").
    • The appropriate percentile depends on how fine the initial grid is. This will also affect the amount of while iterations, and the optimal initial value for cnt.

    function [xBest,yBest,R] = q42806059
    rng(1)
    x=rand(1,100)*5;
    y=rand(1,100)*5;
    
    %% Find the approximate region(s) where there exists a point farthest from all the rest:
    xExtent = linspace(min(x),max(x),numel(x)); 
    yExtent = linspace(min(y),max(y),numel(y)).';
    % Create a grid:
    [XX,YY] = meshgrid(xExtent,yExtent);
    % Compute pairwise distance from grid points to free points:
    D = reshape(min(pdist2([XX(:),YY(:)],[x(:),y(:)]),[],2),size(XX));
    % Intermediate plot:
    % figure(); plot(x,y,'.k'); hold on; contour(XX,YY,D); axis square; grid on;
    % Remove irrelevant candidates:
    D(D xExtent | D > yExtent | D > yExtent(end)-yExtent | D > xExtent(end)-xExtent) = NaN;
    %% Keep only the region with the largest distance
    L = bwlabel(~isnan(D));
    [~,I] = max(table2array(regionprops('table',L,D,'MaxIntensity')));
    D(L~=I) = NaN;
    % surf(XX,YY,D,'EdgeColor','interp','FaceColor','interp');
    %% Iterate until sufficient precision:
    xExtent = xExtent(~isnan(min(D,[],1,'omitnan')));
    yExtent = yExtent(~isnan(min(D,[],2,'omitnan')));
    cnt = 1; % increase or decrease according to the nature of the problem
    while true
      % Same ideas as above, so no explanations:
      xExtent = linspace(xExtent(1),xExtent(end),20); 
      yExtent = linspace(yExtent(1),yExtent(end),20).'; 
      [XX,YY] = meshgrid(xExtent,yExtent);
      D = reshape(min(pdist2([XX(:),YY(:)],[x(:),y(:)]),[],2),size(XX));
      D(D

    The result I'm getting for Ander's example data is [x,y,r] = [0.7832, 2.0694, 0.7815] (which is the same). The execution time is about half of Ander's solution.

    Here are the intermediate plots:

    Contour of the largest (clear) distance from a point to the set of all provided points:

    After considering distance from the boundary, keeping only the top 5% of distant points, and considering only the region which contains the largest distance (the piece of surface represents the kept values):

    And finally:

提交回复
热议问题