admin管理员组文章数量:1321048
Assuming we have a matrix M of size N^2 x N^2 elements (e.g., 9x9), what's the fastest way to split it into say 3x3 segments (each with 3x3 elements).
One way that comes to mind is the following:
M = magic(9);
N = 3;
m = mat2cell(M, N * ones(1, size(M, 1) / N), ...
N * ones(1, size(M, 2) / N));
I, however, do not prefer the use of cells. I was curious if there is a way to split the matrix and store the segments in the form of a 3D matrix using a column-major indexing for the segments (e.g., the first segment m{1} becomes m(:, :, 1) and the second segment m{2} becomes m(:, :, 2), and so on).
Assuming we have a matrix M of size N^2 x N^2 elements (e.g., 9x9), what's the fastest way to split it into say 3x3 segments (each with 3x3 elements).
One way that comes to mind is the following:
M = magic(9);
N = 3;
m = mat2cell(M, N * ones(1, size(M, 1) / N), ...
N * ones(1, size(M, 2) / N));
I, however, do not prefer the use of cells. I was curious if there is a way to split the matrix and store the segments in the form of a 3D matrix using a column-major indexing for the segments (e.g., the first segment m{1} becomes m(:, :, 1) and the second segment m{2} becomes m(:, :, 2), and so on).
Share Improve this question asked Jan 17 at 15:36 the_wickedthe_wicked 1979 bronze badges 1- You already got quite a few answers, but see if this helps – Luis Mendo Commented Jan 17 at 19:46
4 Answers
Reset to default 10You can combine reshape
with permute
, e.g. like so:
reshape(permute(reshape(M, N,N,N,N), [1,3, 2,4]), N,N, N*N)
The inner reshape
has your intended "cells" split into dimensions 1 and 3, which permute
shifts into dimensions 1 and 2. The outer reshape
may be omitted, if you are ok with having a 4D matrix.
After using mat2cell
, you can concatenate the 2D matrices into a 3D matrix with
m = cat( 3, m{:} );
This will satisfy "m{1} becomes m(:, :, 1)" etc.
A different option would be to take each strip of N
rows and reshape
them directly into an NxNxN
matrix of segments, assigning them as the next chunk of the NxNx(N^2)
output matrix
m = NaN(N,N,N^2);
for ii = 1:N:N^2
m(:,:,ii:(ii+N-1)) = reshape( M(ii:(ii+N-1),:), N, N, N );
end
Note that the segments in these two options are in a different order (the first goes down then across for sub-matrices, the latter goes across then down). If you wanted this loop and reshape version to match the mat2cell
version exactly you would need to do a couple of transpose operations with the reshape
to get the ordering right
m = NaN(N,N,N^2);
for ii = 1:N:N^2
m(:,:,ii:(ii+N-1)) = pagetranspose( reshape( M(:,ii:(ii+N-1)).', N, N, N ) );
end
There is only a very small performance penalty for doing the additional transpose operations.
Update with benchmarking
I was curious which of the options above would be faster, so wrote the benchmark at the bottom here (wrapper for the code suggested in the answer above). Here is the resulting plot, so looping and assigning directly into a numeric matrix is faster than going via a cell regardless of N
:
I've also included chtz's answer which just uses reshape
and permute, and gives the same result as the mat2cell
and pagetranspose
options above much faster, and with less dependency on N
, so I would recommend their solution.
I've also included Luis' answer for completeness.
Benchmarking code:
Nmax = 17;
t = zeros(Nmax,2);
for N = 2:Nmax
M = (1:N^2) + 0.1*(1:N^2).';
t(N,1) = timeit( @() opt1(N,M) );
t(N,2) = timeit( @() opt2(N,M) );
t(N,3) = timeit( @() opt3(N,M) );
t(N,4) = timeit( @() opt4(N,M) );
t(N,5) = timeit( @() opt5(N,M) );
end
figure(1); clf; hold on; grid on; legend( 'show', 'fontsize', 14 );
plot( 1:Nmax, t(:,1), 'displayname', 'mat2cell and cat', 'linewidth', 2 );
plot( 1:Nmax, t(:,2), 'displayname', 'loop and reshape', 'linewidth', 2 );
plot( 1:Nmax, t(:,3), 'displayname', 'loop and reshape (2)', 'linewidth', 2 );
plot( 1:Nmax, t(:,4), 'displayname', 'reshape and permute', 'linewidth', 2 );
plot( 1:Nmax, t(:,5), 'displayname', 'im2col', 'linewidth', 2 );
ylabel( 'Time (sec)' );
xlabel( 'N' );
m = opt3( N, M );
function m = opt1( N, M )
m = mat2cell(M, N * ones(1, size(M, 1) / N), ...
N * ones(1, size(M, 2) / N));
m = cat( 3, m{:} );
end
function m = opt2( N, M )
m = NaN(N,N,N^2);
for ii = 1:N:N^2
m(:,:,ii:(ii+N-1)) = reshape( M(ii:(ii+N-1),:), N, N, N );
end
end
function m = opt3( N, M )
m = NaN(N,N,N^2);
for ii = 1:N:N^2
m(:,:,ii:(ii+N-1)) = pagetranspose( reshape( M(:,ii:(ii+N-1)).', N, N, N ) );
end
end
function m = opt4( N, M )
m = reshape(permute(reshape(M, N,N,N,N), [1,3, 2,4]), N,N, N*N);
end
function m = opt5( N, M )
m = reshape(im2col(M, [N N], 'distinct'), N, N, []);
end
If you have the Image Procressing Toolbox, you can do it easily with im2col
(but the code is probably slower than the other options):
S = reshape(im2col(M, [N N], 'distinct'), N, N, []);
Could this help you?
m = reshape(M,N,N,N*N);
本文标签: arraysHow to divide a matrix in MATLAB into N2 segments each with NxN elementsStack Overflow
版权声明:本文标题:arrays - How to divide a matrix in MATLAB into N^2 segments each with NxN elements? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742094902a2420486.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论