Matlab 分布粒子图像中自由区域最大圆的拟合

Matlab 分布粒子图像中自由区域最大圆的拟合,matlab,math,image-processing,geometry,particles,Matlab,Math,Image Processing,Geometry,Particles,我正在处理图像,以检测并拟合包含分布粒子的图像任意自由区域中可能的最大圆: (能够检测粒子的位置) 一个方向是定义一个接触任意三点组合的圆,检查该圆是否为空,然后在所有空圆中找到最大的圆。但是,它会导致大量的组合,即C(n,3),其中n是图像中粒子的总数 如果有人能为我提供任何提示或其他方法,我将不胜感激 我不习惯图像处理,所以这只是一个想法: 实现类似高斯滤波器(模糊)的功能,将每个粒子(像素)转换为一个圆形渐变,r=图像大小(所有粒子重叠)。这样,你应该得到一张图片,其中最白的像素应该是最好

我正在处理图像,以检测并拟合包含分布粒子的图像任意自由区域中可能的最大圆:

(能够检测粒子的位置)

一个方向是定义一个接触任意三点组合的圆,检查该圆是否为空,然后在所有空圆中找到最大的圆。但是,它会导致大量的组合,即
C(n,3)
,其中
n
是图像中粒子的总数


如果有人能为我提供任何提示或其他方法,我将不胜感激

我不习惯图像处理,所以这只是一个想法:

实现类似高斯滤波器(模糊)的功能,将每个粒子(像素)转换为一个圆形渐变,r=图像大小(所有粒子重叠)。这样,你应该得到一张图片,其中最白的像素应该是最好的结果。不幸的是,gimp中的演示失败了,因为极端的模糊使点消失了


或者,您可以通过标记一个区域中的所有相邻像素(例如:r=4)来增量扩展所有现有像素,剩下的像素将是相同的结果(与任何像素的距离最大的像素)

让我们做一些数学吧,我的朋友,因为数学永远都会结束

维基百科:

在数学中,Voronoi图是将一个平面划分为 基于到平面特定子集中点的距离的面域

例如:

rng(1)
x=rand(1,100)*5;
y=rand(1,100)*5;


voronoi(x,y);

这个图表的好处是,如果你注意到,这些蓝色区域的所有边/顶点都与它们周围的点的距离相等。因此,如果我们知道顶点的位置,并计算到最近点的距离,那么我们可以选择距离最大的顶点作为圆心

有趣的是,Voronoi区域的边也被定义为Delaunay三角剖分生成的三角形的外心

如果我们计算区域的Delaunay三角剖分,以及它们的外心

dt=delaunayTriangulation([x;y].');
cc=circumcenter(dt); %voronoi edges
并计算外圆中心和定义每个三角形的任何点之间的距离:

for ii=1:size(cc,1)
    if cc(ii,1)>0 && cc(ii,1)<5 && cc(ii,2)>0 && cc(ii,2)<5
    point=dt.Points(dt.ConnectivityList(ii,1),:); %the first one, or any other (they are the same distance)
    distance(ii)=sqrt((cc(ii,1)-point(1)).^2+(cc(ii,2)-point(2)).^2);
    end
end
现在让我们来绘图

hold on

ang=0:0.01:2*pi; 
xp=r*cos(ang);
yp=r*sin(ang);

point=cc(ind,:);

voronoi(x,y)
triplot(dt,'color','r','linestyle',':')
plot(point(1)+xp,point(2)+yp,'k');
plot(point(1),point(2),'g.','markersize',20);

请注意,圆心是如何位于Voronoi图的一个顶点上的


注意:这将在[0-5]、[0-5]内找到中心。您可以轻松地修改它以更改此约束。您还可以尝试在感兴趣的区域(而不仅仅是中心)内找到适合其整体的圆。这需要在获得最大值的末端进行一个小的添加。

您可以使用图像处理工具箱计算图像的距离变换。这可以看作是创建voronoi图的一种方法,在@AnderBiguri的回答中有很好的解释

img = imread('AbmxL.jpg');
%convert the image to a binary image
points = img(:,:,3)<200;
%compute the distance transform of the binary image
dist = bwdist(points);
%find the circle that has maximum radius
radius = max(dist(:));
%find position of the circle
[x y] = find(dist == radius);
imshow(dist,[]);
hold on
plot(y,x,'ro');
img=imread('AbmxL.jpg');
%将图像转换为二进制图像

points=img(:,:,3)我想提出另一个基于网格搜索的解决方案,并进行优化。它不像Ander的那样先进,也不像rahnema1的那样短,但应该很容易理解和理解。而且,它运行得相当快

该算法包含几个阶段:

  • 我们生成一个均匀分布的网格
  • 我们找到网格中的点到所有提供点的最小距离
  • 我们丢弃距离低于某个百分位(例如第95位)的所有点
  • 我们选择包含最大距离的区域(如果初始网格足够精细,则该区域应包含正确的中心)
  • 我们在所选区域周围创建一个新的网格,然后再次查找距离(这部分显然是次优的,因为距离是计算到所有点的,包括远处和不相关的点)
  • 我们在区域内迭代细化,同时关注前5%值的方差->如果它低于我们打破的某个预设阈值
  • 几点注意:

    • 我假设圆不能超出散乱点的范围(即散乱的边界正方形充当“看不见的墙”)
    • 适当的百分位数取决于初始网格的精细程度。这也会影响
      迭代时的
      数量,以及
      cnt
      的最佳初始值
    函数[xBest,yBest,R]=q42806059
    rng(1)
    x=兰特(1100)*5;
    y=兰特(1100)*5;
    %%查找存在距离所有其他点最远点的近似区域:
    xExtent=linspace(min(x)、max(x)、numel(x));
    yExtent=linspace(最小(y)、最大(y)、numel(y));
    %创建网格:
    [XX,YY]=meshgrid(xExtent,yExtent);
    %计算从栅格点到自由点的成对距离:
    D=重塑(最小值(pdist2([XX(:),YY(:)],[x(:),y(:)],[],2),尺寸(XX));
    %中间地块:
    %图();图(x,y,'.k');等等轮廓线(XX,YY,D);轴线广场;网格化;
    %删除不相关的候选人:
    D(D xExtent | D>yExtent | D>yExtent(end)-yExtent | D>xExtent(end)-xExtent)=NaN;
    %%仅保留距离最大的区域
    L=bwlabel(~isnan(D));
    [~,I]=max(表2array(regionprops('table',L,D,'MaxIntensity'));
    D(L~=I)=NaN;
    %surf(XX,YY,D,'EdgeColor','interp','FaceColor','interp');
    %%迭代直到达到足够的精度:
    xExtent=xExtent(~isnan(min(D,[],1,'omitnan'));
    yExtent=yExtent(~isnan(min(D,[],2,'omitnan'));
    cnt=1;%根据问题的性质增加或减少
    虽然是真的
    %与上述想法相同,因此无需解释:
    xExtent=linspace(xExtent(1),xExtent(end),20);
    yExtent=linspace(yExtent(1),yExtent(end),20)。”;
    [XX,YY]=meshgrid(xExtent,yExtent);
    D=重塑(最小值(pdist2([XX(:),YY(:)],[x(:),y(:)],[],2),尺寸(XX));
    
    D(D事实上,这个问题可以通过“直接搜索”(如中所示)来解决,这意味着人们可以将其视为一个问题。有多种方法可以解决此类问题,每种方法都适用于特定场景
    img = imread('AbmxL.jpg');
    %convert the image to a binary image
    points = img(:,:,3)<200;
    %compute the distance transform of the binary image
    dist = bwdist(points);
    %find the circle that has maximum radius
    radius = max(dist(:));
    %find position of the circle
    [x y] = find(dist == radius);
    imshow(dist,[]);
    hold on
    plot(y,x,'ro');
    
    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<prctile(D(:),95)) = NaN;
    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<prctile(D(:),95)) = NaN;
      I = find(D == max(D(:)));
      xBest = XX(I);
      yBest = YY(I);  
      if nanvar(D(:)) < 1E-10 || cnt == 10
        R = D(I);
        break
      end
      xExtent = (1+[-1 +1]*10^-cnt)*xBest;
      yExtent = (1+[-1 +1]*10^-cnt)*yBest;
      cnt = cnt+1;
    end
    % Finally:
    % rectangle('Position',[xBest-R,yBest-R,2*R,2*R],'Curvature',[1 1],'EdgeColor','r');
    
    function [x,y,r] = q42806059b(cloudOfPoints)
    % Problem setup
    if nargin == 0
      rng(1)
      cloudOfPoints = rand(100,2)*5; % equivalent to Ander's initialization.
    end
    %{
    figure(); plot(cloudOfPoints(:,1),cloudOfPoints(:,2),'.w'); hold on; axis square;
    set(gca,'Color','k'); plot(0.7832,2.0694,'ro'); plot(0.7832,2.0694,'r*');
    %}
    nVariables = 3;
    options = optimoptions(@ga,'UseVectorized',true,'CreationFcn',@gacreationuniform,...
                           'PopulationSize',1000);
    
    S = max(cloudOfPoints,[],1); L = min(cloudOfPoints,[],1); % Find geometric bounds:
    % In R2017a: use [S,L] = bounds(cloudOfPoints,1);
    
    % Here we also define distance-from-boundary constraints.
    g = ga(@(g)vectorized_fitness(g,cloudOfPoints,[L;S]), nVariables,...
           [],[], [],[], [L 0],[S min(S-L)], [], options);
    x = g(1); y = g(2); r = g(3);
    %{
    plot(x,y,'ro'); plot(x,y,'r*'); 
    rectangle('Position',[x-r,y-r,2*r,2*r],'Curvature',[1 1],'EdgeColor','r'); 
    %}
    
    function f = vectorized_fitness(genes,pts,extent)
    % genes = [x,y,r]
    % extent = [Xmin Ymin; Xmax Ymax]
    % f, the fitness, is the largest radius.
    f = min(pdist2(genes(:,1:2), pts, 'euclidean'), [], 2);
    % Instant death if circle contains a point:
    f( f < genes(:,3) ) = Inf;
    % Instant death if circle is too close to boundary:
    f( any( genes(:,3) > genes(:,1:2) - extent(1,:) | ...
            genes(:,3) > extent(2,:) - genes(:,1:2), 2) ) = Inf;
    % Note: this condition may possibly be specified using the A,b inputs of ga().
    f(isfinite(f)) = -genes(isfinite(f),3);
    %DEBUG: 
    %{
         scatter(genes(:,1),genes(:,2),10 ,[0, .447, .741] ,'o'); % All
     z = ~isfinite(f); scatter(genes(z,1),genes(z,2),30,'r','x'); % Killed
     z =  isfinite(f); scatter(genes(z,1),genes(z,2),30,'g','h'); % Surviving
     [~,I] = sort(f); scatter(genes(I(1:5),1),genes(I(1:5),2),30,'y','p'); % Elite
    %}