获取与点集的最小坐标距离矩阵

时间:2016-05-10 12:18:54

标签: matlab

我有一组点或坐标,如{(3,3),(3,4),(4,5),...},并希望建立一个与此点集的距离最小的矩阵。让我举例说明使用一个可运行的例子:

width = 10;
height = 10;

% Get min distance to those points
pts = [3 3; 3 4; 3 5; 2 4];

sumSPts = length(pts);

% Helper to determine element coordinates
[cols, rows] = meshgrid(1:width, 1:height);
PtCoords = cat(3, rows, cols);

AllDistances = zeros(height, width,sumSPts);

% To get Roh_I of evry pt
for k = 1:sumSPts

    % Get coordinates of current Scribble Point
    currPt = pts(k,:);

    % Get Row and Col diffs
    RowDiff = PtCoords(:,:,1) - currPt(1);
    ColDiff = PtCoords(:,:,2) - currPt(2);

    AllDistances(:,:,k) = sqrt(RowDiff.^2 + ColDiff.^2);

end

MinDistances = min(AllDistances, [], 3);

此代码运行完全正常,但我必须处理大约700个百万条目的矩阵大小(高度= 700,宽度= 500,sumSPts = 2k),这会减慢计算速度。是否有更好的算法来加快速度?

1 个答案:

答案 0 :(得分:2)

如评论中所述,您没有必要将所有内容放入一个巨大的矩阵中并处理巨大的矩阵。你可以:

<强> 1。将pts矩阵切成相当小的切片(比如长度为100)

<强> 2。循环切片并计算这些点上的Mindistances切片

第3。采取全球最小化

tic

Mindistances=[];

width = 500;
height = 700;

Np=2000;

pts = [randi(width,Np,1) randi(height,Np,1)];

SliceSize=100;

[Xcoords,Ycoords]=meshgrid(1:width,1:height);


% Compute the minima for the slices from 1 to floor(Np/SliceSize)
for i=1:floor(Np/SliceSize)

    % Calculate indexes of the next slice
    SliceIndexes=((i-1)*SliceSize+1):i*SliceSize


    % Get the corresponding points and reshape them to a vector along the 3rd dim.
    Xpts=reshape(pts(SliceIndexes,1),1,1,[]);
    Ypts=reshape(pts(SliceIndexes,2),1,1,[]);

    % Do all the diffs between your coordinates and your points using bsxfun singleton expansion
    Xdiffs=bsxfun(@minus,Xcoords,Xpts);
    Ydiffs=bsxfun(@minus,Ycoords,Ypts);

    % Calculate all the distances of the slice in one call
    Alldistances=bsxfun(@hypot,Xdiffs,Ydiffs);

    % Concatenate the mindistances
    Mindistances=cat(3,Mindistances,min(Alldistances,[],3));


end

% Check if last slice needed
if mod(Np,SliceSize)~=0

    % Get the corresponding points and reshape them to a vector along the 3rd dim.
    Xpts=reshape(pts(floor(Np/SliceSize)*SliceSize+1:end,1),1,1,[]);
    Ypts=reshape(pts(floor(Np/SliceSize)*SliceSize+1:end,2),1,1,[]);

    % Do all the diffs between your coordinates and your points using bsxfun singleton expansion
    Xdiffs=bsxfun(@minus,Xcoords,Xpts);
    Ydiffs=bsxfun(@minus,Ycoords,Ypts);

    % Calculate all the distances of the slice in one call
    Alldistances=bsxfun(@hypot,Xdiffs,Ydiffs);

    % Concatenate the mindistances
    Mindistances=cat(3,Mindistances,min(Alldistances,[],3));

end

% Get global minimum
Mindistances=min(Mindistances,[],3);

toc
  

经过的时间是9.830051秒。

注意:

你最终不会做更少的计算。但是你的记忆密集程度要低得多(700M双打需要45G记忆),从而加快了过程(借助矢量化)以及

关于bsxfun单身扩张

bsxfun的一大优势在于,您无需为其值相同的矩阵提供数据。

例如:

假设我有两个向量XY定义为:

X=[1 2]; % row vector X
Y=[1;2]; % Column vector Y

我希望为2x2构建Z矩阵Z(i,j)=X(i)+Y(j) 1<=i<=2 and 1<=j<=2

假设您不知道meshgrid的存在(示例有点过于简单),那么您将不得不这样做:

Xs=repmat(X,2,1);
Ys=repmat(Y,1,2);
Z=Xs+Ys;

使用bsxfun时,您可以这样做:

Z=bsxfun(@plus,X,Y);

例如,要计算Z(2,2)的值,bsxfun会自动获取XY的第二个值并进行计算。这样做的好处是可以节省大量的内存空间(在本例中无需定义XsYs),并且在使用大矩阵时速度更快。

Bsxfun与Repmat

如果您对比较bsxfunrepmat之间的计算时间感兴趣,这里有两个优秀(单词甚至不够强大)来自 Divakar :

Comparing BSXFUN and REPMAT

BSXFUN on memory efficiency with relational operations