我有一组点或坐标,如{(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),这会减慢计算速度。是否有更好的算法来加快速度?
答案 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
的一大优势在于,您无需为其值相同的矩阵提供数据。
例如:
假设我有两个向量X
和Y
定义为:
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
会自动获取X
和Y
的第二个值并进行计算。这样做的好处是可以节省大量的内存空间(在本例中无需定义Xs
和Ys
),并且在使用大矩阵时速度更快。
如果您对比较bsxfun
和repmat
之间的计算时间感兴趣,这里有两个优秀(单词甚至不够强大)来自 Divakar :