Matlab,生成并绘制在三角形内部分布的点云

6
我正在尝试生成一个在三角形内均匀分布的二维点云。到目前为止,我已经实现了以下功能:

Matlab plot

我使用的代码是这样的:
N = 1000;
X = -10:0.1:10;
for i=1:N
    j = ceil(rand() * length(X));
    x_i = X(j);
    y_i = (10 - abs(x_i)) * rand;

    E(:, i) = [x_i y_i];
end

然而,很明显在左右两个角落中,这些点并不是均匀分布的。我该如何改善这种结果呢?我一直在尝试寻找不同的形状,但是没有什么好的效果。

4个回答

9

首先,您需要思考一个问题,如何使三角形内的点分布均匀。

简言之,只要给出三角形的所有三个顶点,就可以通过以下方法转换两个均匀分布的随机值:

N = 1000;                    % # Number of points
V = [-10, 0; 0, 10; 10, 0];  % # Triangle vertices, pairs of (x, y)
t = sqrt(rand(N, 1));
s = rand(N, 1);
P = (1 - t) * V(1, :) + bsxfun(@times, ((1 - s) * V(2, :) + s * V(3, :)), t);

这将产生一组在指定三角形内均匀分布的点:
scatter(P(:, 1), P(:, 2), '.')

这里输入图片描述

请注意,此解决方案不涉及重复条件操作随机数,因此不可能陷入无限循环。

如需进一步阅读,请查看本文


你能否解释一下你是如何计算P的?或者告诉我在哪里可以阅读到你使用的公式?谢谢! - Ayushi Jha
1
@CyberLingo 基本上,它随机生成一个点(由ts表示的x,y),并将其重新映射到由V表示的三角形所限制的空间中。 P是映射矩阵和(x,y)的乘积。请注意,随机化的t中的sqrt只是简化最终计算乘积的一种方式。但是,我认为更容易指向一些解释得更好的链接,例如此问题此链接... - Eitan T
1
@CyberLingo 还有,请注意这个计算是对点数组进行随机化(因此得到一个点数组)。因此在计算 'P' 时使用了 bsxfun - Eitan T
1
谢谢您的解释! - Ayushi Jha

2

从你构建的点的方式来看,这种点集中是可以预期的。你的点沿着X轴均匀分布。在三角形的极端端点处,与三角形中心大约有相同数量的点存在,但是它们分布在一个更小的区域内。

我能想到的第一种最好的方法是:暴力破解。将点等距分布在一个更大的区域中,然后删除那些超出你感兴趣的区域的点。

N = 1000;
points = zeros(N,2);
n = 0;
while (n < N)
    n = n + 1;
    x_i = 20*rand-10; % generate a number between -10 and 10
    y_i = 10*rand; % generate a number between 0 and 10
    if (y_i > 10 - abs(x_i)) % if the points are outside the triangle
       n = n - 1; % decrease the counter to try to generate one more point
    else % if the point is inside the triangle
       points(n,:) = [x_i y_i]; % add it to a list of points
    end
end

% plot the points generated
plot(points(:,1), points(:,2), '.');
title ('1000 points randomly distributed inside a triangle');

我已经贴出的代码的结果是: 由上述代码生成的图形

一个重要的免责声明: 随机分布并不意味着“均匀”分布!如果您从均匀分布中随机生成数据,那么这并不意味着它将沿着三角形“均匀地”分布。实际上,您会看到一些点的聚集。


1
在MATLAB中手动更改for循环的迭代变量不是一个好主意。我认为它的行为不会像你期望的那样。 - Eitan T
@Castilho - 在Matlab中,您不能在for循环内更改循环变量。尝试以下代码 for ii=1:2, ii=1, end;,这个循环将只执行两次,并且不会导致无限循环。 - Shai
以上代码在Matlab R2011a上运行良好,如图所示。可以尝试一下 ;) - Castilho
是的,循环可以轻松更改为使用while循环。for循环是第一种方法,因为它更容易编写。根据我的经验,您可以在其中更改循环变量,前提是没有嵌套循环。但是,我将把代码更改为while循环,因为它确实更好。(附言:该代码适用于5个点、1000个点和100000个点) - Castilho
@Castilho -(关于for版本):当您说“代码有效”时,您确定它确切地生成了N个点吗?由于Matlab的for迭代器的行为,似乎有相当多的点落在(0,0)处。在您的图中,有一个点在(0,0)处,我怀疑实际上是一堆点叠加在一起...请参阅我的评论,关于for ii=1:2, ii=1, end; - Shai
1
你说得对,循环不会重复执行。感谢指出这一点。吸取了教训 :) http://blogs.mathworks.com/loren/2006/07/19/how-for-works/ - Castilho

1
你可以想象将三角形垂直分成两半,并移动其中一半,与另一半一起组成一个矩形。现在你可以在矩形中均匀采样,这很容易,然后再将一半的三角形移回来。
此外,使用单位长度更容易(矩形变成正方形),然后将三角形拉伸到所需的尺寸。
x = [-10 10]; % //triangle base
y = [0 10]; % //triangle height
N = 1000; %// number of points

points = rand(N,2); %// sample uniformly in unit square
ind = points(:,2)>points(:,1); %// points to be unfolded 
points(ind,:) = [2-points(ind,2) points(ind,1)]; %// unfold them
points(:,1) = x(1) + (x(2)-x(1))/2*points(:,1); %// stretch x as needed
points(:,2) = y(1) + (y(2)-y(1))*points(:,2); %// stretch y as needed
plot(points(:,1),points(:,2),'.')

enter image description here


0
我们可以将这种情况概括。如果您想从欧几里得空间中的某个(n-1)维单纯形中均匀地采样点(不一定是三角形-它可以是任何凸多面体),只需从具有参数1的对称n维狄利克雷分布中采样向量-这些是相对于多面体顶点的凸(或重心)坐标。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接