我正在处理图像,以检测并拟合包含分布式粒子的图像的任何自由区域中的最大圆圈:
(能够检测粒子的位置)。
一个方向是定义一个圆圈,触摸任意三点组合,检查圆圈是否为空,然后在所有空圆圈中找到最大的圆圈。但是,它导致了大量的组合,即C(n,3)
,其中n
是图像中的粒子总数。
如果有人能为我提供任何我可以探索的提示或替代方法,我将不胜感激。
答案 0 :(得分:89)
让我的朋友做一些数学,因为数学总会到最后!
百科:
在数学中,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
然后我们将所有可能的圆圈的中心(cc
)和半径(distance
)放在其中。我们只需要最大的一个!
[r,ind]=max(distance); %Tada!
现在让我们绘制
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]中找到中心。您可以轻松修改它以更改此约束。您还可以尝试在感兴趣的区域内找到适合其整体的圆圈(而不仅仅是中心)。这将需要在最终获得最大值的一小部分。
答案 1 :(得分:22)
我想提出另一种基于网格搜索和优化的解决方案。它不像Ander那样先进,也不像rahnema1那么短,但它应该非常容易理解。而且,它运行得非常快。
该算法包含几个阶段:
几点说明:
while
次迭代的数量,以及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<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');
我得到的Ander示例数据的结果是[x,y,r] = [0.7832, 2.0694, 0.7815]
(这是相同的)。执行时间约为Ander解决方案的一半。
从一个点到所有提供点的集合的最大(清晰)距离的轮廓:
在考虑距离边界的距离后,仅保留距离点的前5%,并且仅考虑包含最大距离的区域(表面表示保留的值):
答案 2 :(得分:13)
您可以使用图像处理工具箱中的bwdist来计算图像的距离变换。这可以被视为一种创建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');
答案 3 :(得分:13)
使用“直接搜索”(可以在another answer中看到)解决此问题的事实意味着可以将此视为global optimization问题。存在各种方法来解决这些问题,每种方法都适用于某些场景。出于个人的好奇心,我决定使用遗传算法来解决这个问题。
一般来说,这种算法要求我们将解决方案视为一组在某种“适应度函数”下经历“进化”的“基因”。碰巧的是,在这个问题上很容易识别基因和适应度函数:
x
,y
,r
。r
(或最小-r
,因为算法需要最小化的函数r
大于距最近提供点的欧氏距离(即圆圈包含一个点),则生物体“死亡”。下面是这种算法的基本实现(“ basic ”,因为它完全没有优化,并且有很多优化空间 没有双关语 < / sup>在这个问题上)。
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
%}
这是典型运行的47代的“延时”情节:
(其中蓝点是当前一代,红十字是“insta-killed”生物,绿卦是“非insta-killed”生物,红圈标志着目的地。)
答案 4 :(得分:1)
我不习惯图像处理,所以这只是一个想法:
实现像高斯滤镜(模糊)之类的东西,它将每个粒子(像素)转换为圆形渐变,其中r = image_size(所有这些都重叠)。这样,你应该得到一张图片,其中最白的像素应该是最好的结果。不幸的是,gimp的演示失败了,因为极端的模糊使点消失了。
或者,您可以通过标记区域中的所有相邻像素来增加所有现有像素(例如:r = 4),左边的像素将是相同的结果(与任何像素的距离最大的那些)