有什么最简单的方法来计算这个区域的面积?有没有在 Matlab 中轻松完成的方法?
我通过找到边界上大约 40 个点并计算 Matlab 中多边形区域的面积来进行了多边形逼近,但我想知道是否有另一种比找到边界上的 40 个点更少费力的方法。
考虑以下例子:
%# random points
x = randn(300,1);
y = randn(300,1);
%# convex hull
dt = DelaunayTri(x,y);
k = convexHull(dt);
%# area of convex hull
ar = polyarea(dt.X(k,1),dt.X(k,2))
%# plot
plot(dt.X(:,1), dt.X(:,2), '.'), hold on
fill(dt.X(k,1),dt.X(k,2), 'r', 'facealpha', 0.2);
hold off
title( sprintf('area = %g',ar) )
有一个由Doug Hull制作的短视频,解决了这个精确问题。
我发表了第二篇答案,受到@Jean-FrançoisCorbett提出的解决方案的启发。
首先,我创建了随机数据,并使用交互式刷子工具,删除了一些点,使其看起来像所需的“肾”形状...
为了有一个基准比较,我们可以手动跟踪包围区域,使用IMFREEHAND函数(我使用的是笔记本电脑的触摸板,所以绘画不太准确!)。然后我们使用POLYAREA计算此多边形的面积。就像我的上一个答案一样,我也计算了凸包:
现在,基于我之前回答的另一个SO问题(2D直方图),想法是在数据上放置网格。网格分辨率的选择非常重要,我的数据使用numBins = [20 30];
。
接下来,我们计算包含足够点数的正方形数量(我使用至少1
个点作为阈值,但您可以尝试更高的值)。最后,我们将此计数乘以一个网格正方形的面积,以获得近似的总面积。
%### DATA ###
%# some random data
X = randn(100000,1)*1;
Y = randn(100000,1)*2;
%# HACK: remove some point to make data look like a kidney
idx = (X<-1 & -4<Y & Y<4 ); X(idx) = []; Y(idx) = [];
%# or use the brush tool
%#brush on
%### imfreehand ###
figure
line('XData',X, 'YData',Y, 'LineStyle','none', ...
'Color','b', 'Marker','.', 'MarkerSize',1);
daspect([1 1 1])
hROI = imfreehand('Closed',true);
pos = getPosition(hROI); %# pos = wait(hROI);
delete(hROI)
%# total area
ar1 = polyarea(pos(:,1), pos(:,2));
%# plot
hold on, plot(pos(:,1), pos(:,2), 'Color','m', 'LineWidth',2)
title('Freehand')
%### 2D histogram ###
%# center of bins
numBins = [20 30];
xbins = linspace(min(X), max(X), numBins(1));
ybins = linspace(min(Y), max(Y), numBins(2));
%# map X/Y values to bin-indices
Xi = round( interp1(xbins, 1:numBins(1), X, 'linear', 'extrap') );
Yi = round( interp1(ybins, 1:numBins(2), Y, 'linear', 'extrap') );
%# limit indices to the range [1,numBins]
Xi = max( min(Xi,numBins(1)), 1);
Yi = max( min(Yi,numBins(2)), 1);
%# count number of elements in each bin
H = accumarray([Yi(:), Xi(:)], 1, [numBins(2) numBins(1)]);
%# total area
THRESH = 0;
sqNum = sum(H(:)>THRESH);
sqArea = (xbins(2)-xbins(1)) * (ybins(2)-ybins(1));
ar2 = sqNum*sqArea;
%# plot 2D histogram/thresholded_histogram
figure, imagesc(xbins, ybins, H)
axis on, axis image, colormap hot; colorbar; %#caxis([0 500])
title( sprintf('2D Histogram, bins=[%d %d]',numBins) )
figure, imagesc(xbins, ybins, H>THRESH)
axis on, axis image, colormap gray
title( sprintf('H > %d',THRESH) )
%### convex hull ###
dt = DelaunayTri(X,Y);
k = convexHull(dt);
%# total area
ar3 = polyarea(dt.X(k,1), dt.X(k,2));
%# plot
figure, plot(X, Y, 'b.', 'MarkerSize',1), daspect([1 1 1])
hold on, fill(dt.X(k,1),dt.X(k,2), 'r', 'facealpha',0.2); hold off
title('Convex Hull')
%### plot ###
figure, hold on
%# plot histogram
imagesc(xbins, ybins, H>=1)
axis on, axis image, colormap gray
%# plot grid lines
xoff = diff(xbins(1:2))/2; yoff = diff(ybins(1:2))/2;
xv1 = repmat(xbins+xoff,[2 1]); xv1(end+1,:) = NaN;
yv1 = repmat([ybins(1)-yoff;ybins(end)+yoff;NaN],[1 size(xv1,2)]);
yv2 = repmat(ybins+yoff,[2 1]); yv2(end+1,:) = NaN;
xv2 = repmat([xbins(1)-xoff;xbins(end)+xoff;NaN],[1 size(yv2,2)]);
xgrid = [xv1(:);NaN;xv2(:)]; ygrid = [yv1(:);NaN;yv2(:)];
line(xgrid, ygrid, 'Color',[0.8 0.8 0.8], 'HandleVisibility','off')
%# plot points
h(1) = line('XData',X, 'YData',Y, 'LineStyle','none', ...
'Color','b', 'Marker','.', 'MarkerSize',1);
%# plot convex hull
h(2) = patch('XData',dt.X(k,1), 'YData',dt.X(k,2), ...
'LineWidth',2, 'LineStyle','-', ...
'EdgeColor','r', 'FaceColor','r', 'FaceAlpha',0.5);
%# plot freehand polygon
h(3) = plot(pos(:,1), pos(:,2), 'g-', 'LineWidth',2);
%# compare results
title(sprintf('area_{freehand} = %g, area_{grid} = %g, area_{convex} = %g', ...
ar1,ar2,ar3))
legend(h, {'Points' 'Convex Jull','FreeHand'})
hold off
以下是三种方法的最终结果,同时显示面积近似值:
我对此知之甚少,所以不要过分相信...考虑进行Delaunay三角剖分。然后删除任何长于某个最大值的外壳(外部)边缘。重复直到没有可删除的内容。填充剩余的三角形。
这将使一些离群点成为孤立点。
我建议使用空间填充曲线,例如z曲线或更好的moore曲线。 SFC填满整个空间,并且适合索引每个点。例如,对于所有f(x)= y,您可以按升序对曲线上的点进行排序,并从该结果中取出尽可能多的点,直到获得完整的往返行程。然后,您可以使用这些点来计算面积。由于有许多点,您可能希望使用较少的点并使用聚类使结果不太准确。
我认为你可以使用凸包算法来获取边界点,限制边长(应该按垂直轴对点进行排序)。这样它将遵循您区域的非凸性。我建议长度为0.02。无论如何,您可以尝试使用不同的长度绘制结果并在视觉上检查它。