答案 1: 与其建立一个巨大的边和权重矩阵......使用边列表直接在循环中迭代地构建图形,循环每个维度(行、列、平面)。这个 64x64x10 非常快(秒),但对于大型示例(256x256x1000)运行时间要长得多。要是能开发出一个更快的版本就好了。
X=256;Y=256;Z=1000;
% input matrix of 0-1 values
mat = rand(X,Y,Z);
% matrix of indices for input matrix coordinates
imat = reshape([1:(X*Y*Z)],X,Y,Z);
% initialize empty graph
g = graph();
xdim = size(imat,1);
ydim = size(imat,2);
zdim = size(imat,3);
% create edge list with weights
disp('calculating start/end nodes for edges and associated weights...')
for y = 1:(ydim-1) % loop through all "horizontal" (column) connections in each z plane
% example:
% 1 - 3
% 2 - 4
for z = 1:zdim
nodes1 = imat(:,y,z);
nodes2 = imat(:,y+1,z); % grab column y+1 nodes of plane z
wts = ((1-mat(:,y,z)) + (1-mat(:,y+1,z))) ./ 2; % average of 1-value for each node
g = addedge(g,nodes1,nodes2,wts); % add to graph
end
end
for x = 1:(xdim-1) % loop through all "vertical" (row) connections within each z plane
% example:
% 1 3
% | |
% 2 4
for z = 1:zdim
nodes1 = imat(x,:,z);
nodes2 = imat(x+1,:,z); % grab row x+1 nodes of plane z
wts = ((1-mat(x,:,z)) + (1-mat(x+1,:,z))) ./ 2; % average of 1-value for each node
g = addedge(g,nodes1,nodes2,wts); % add to graph
end
end
for z = 1:(zdim-1) % loop through all "deep" connections across z planes
% example:
% 5 7
% / /
% 1 3
for x = 1:xdim
nodes1 = imat(x,:,z);
nodes2 = imat(x,:,z+1); % grab row x nodes of plane z+1
wts = ((1-mat(x,:,z)) + (1-mat(x,:,z+1))) ./ 2; % average of 1-value for each node
g = addedge(g,nodes1,nodes2,wts); % add to graph
end
end
disp('done.')
figure
spy(adjacency(g))
答案 2: 将链接答案的 4-connected case 扩展到第三维 (https://stackoverflow.com/a/3283732/2371031):
disp("calculating adjacency matrix...")
X=3; Y=3; Z=2;
mat = reshape([1:(X*Y*Z)],X,Y,Z);
[x, y, z] = size(mat); % Get the matrix size
diagVec1 = repmat(repmat([ones(y-1, 1); 0], x, 1), z, 1); % Make the first diagonal vector
% (for y-planar connections)
diagVec1 = diagVec1(1:end-1); % Remove the last value
diagVec2 = repmat([ones(y*(x-1), 1); zeros(x,1)], z, 1); % Make the second diagonal vector
% (for x-planar connections)
diagVec2 = diagVec2(1:end-x); % drop the last x values (zeros)
diagVec3 = ones(x*y*(z-1), 1); % make the third diagonal vector
% (for z-planar connections)
adj = diag(diagVec1, 1)+diag(diagVec2, y)+diag(diagVec3, x*y); % Add the diagonals to a zero matrix
adj = adj+adj.'; % Add the matrix to a transposed copy of
% itself to make it symmetric
disp("done.")
figure
spy(adj)
对于大案例Matlab报错:
Error using diag
Requested 65536000x65536000 (32000000.0GB) array exceeds maximum array size preference. Creation of
arrays greater than this limit may take a long time and cause MATLAB to become unresponsive.
Error in blah (line X)
adj = diag(diagVec1, 1) + diag(diagVec2, y) + diag(diagVec3, x*y); % Add the diagonals to a zero matrix
更新
答案 3:
(@beaker 答案的更新版本)
我很好奇是否可以通过使用 26 连通情况(所有 9 个线性或对角相邻点在上平面,9 个在下平面,8 个在重合平面)来获得改进的最短路径结果。
% 3x3x3 'cube'
X=3;Y=3;Z=3;
% input matrix of 0-1 values
M_wts = rand(X,Y,Z);
M_wts = 1-M_wts;
% matrix of indices for input matrix coordinates
M = reshape([1:(X*Y*Z)],X,Y,Z);
% initialize empty graph
g = graph();
%% Given a 3d matrix M, generate a graph representing
% the 6-connected neighbors.
% Node numbers are equal to node indices in M.
% Edge weights are given by mean of adjacent node values.
[x, y, z] = size(M);
% Initialize Source and Target node vectors and corresponding Weight
S = [];
T = [];
%% 6-connected case:
% List neighboring nodes where S(i) < T(i)
% Neighbors along dimension 1 (x/lateral)
[X1, X2, X3] = ndgrid(1:x-1, 1:y, 1:z);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(2:x, 1:y, 1:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
% Neighbors along dimension 2 (y/vertical)
[X1, X2, X3] = ndgrid(1:x, 1:y-1, 1:z);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(1:x, 2:y, 1:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
% Neighbors along dimension 3 (z/planar)
[X1, X2, X3] = ndgrid(1:x, 1:y, 1:z-1);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(1:x, 1:y, 2:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
%%
% Calculate the weight for each edge
W = mean(M_wts([S, T]), 2);
g = graph(S, T, W);
gplot = plot(g,'EdgeLabel',g.Edges.Weight);
layout(gplot,'force3')
view(3)
%% diagonal connections
% Neighbors within dimension 3 (diagonal xy1)
[X1, X2, X3] = ndgrid(1:x-1, 1:y-1, 1:z);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(2:x, 2:y, 1:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
% Neighbors within dimension 3 (diagonal xy2)
[X1, X2, X3] = ndgrid(1:x-1, 2:y, 1:z);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(2:x, 1:y-1, 1:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
%% across-plane diagonal connections
% Neighbors along dimension 3 (across-plane diagonal xz1)
[X1, X2, X3] = ndgrid(1:x, 1:y-1, 1:z-1);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(1:x, 2:y, 2:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
% Neighbors along dimension 3 (across-plane diagonal xz2)
[X1, X2, X3] = ndgrid(1:x, 2:y, 1:z-1);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(1:x, 1:y-1, 2:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
% Neighbors along dimension 3 (across-plane diagonal yz1)
[X1, X2, X3] = ndgrid(1:x-1, 1:y, 1:z-1);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(2:x, 1:y, 2:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
% Neighbors along dimension 3 (across-plane diagonal yz2)
[X1, X2, X3] = ndgrid(2:x, 1:y, 1:z-1);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(1:x-1, 1:y, 2:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
% Neighbors along dimension 3 (across-plane diagonal xyz1)
[X1, X2, X3] = ndgrid(1:x-1, 1:y-1, 1:z-1);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(2:x, 2:y, 2:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
% Neighbors along dimension 3 (across-plane diagonal xyz2)
[X1, X2, X3] = ndgrid(2:x, 1:y-1, 1:z-1);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(1:x-1, 2:y, 2:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
% Neighbors along dimension 3 (across-plane diagonal xyz3)
[X1, X2, X3] = ndgrid(1:x-1, 2:y, 1:z-1);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(2:x, 1:y-1, 2:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
% Neighbors along dimension 3 (across-plane diagonal xyz4)
[X1, X2, X3] = ndgrid(2:x, 2:y, 1:z-1);
S = [S; sub2ind(size(M), X1(:), X2(:), X3(:))];
[X1, X2, X3] = ndgrid(1:x-1, 1:y-1, 2:z);
T = [T; sub2ind(size(M), X1(:), X2(:), X3(:))];
%% 3D plot it
% Calculate the weight for each edge
W = mean(M_wts([S, T]), 2);
g = graph(S, T, W);
gplot = plot(g,'EdgeLabel',g.Edges.Weight);
layout(gplot,'force3')
view(3)