Unfold 3D Matrix to 2D

5 views (last 30 days)
Claas
Claas on 26 Mar 2019
Answered: Claas on 17 Apr 2019
Hi,
at first glance my question seems easy: I got a 512x512x79 matrix, which is a stack of 79 images. What I now would like to do is convert it to 40448x512 matrix which is a straightforward job for reshape, BUT I don't get it to work I'd like to:
I don't want to put the matrices just side by side or underneath each other, but rahter unfold or unwrap it, i.e. imagine the 3D matrix is the outer shell of a cylinder. Then I would like to get a rectangular field as a result.
Thanks a lot in advance!
  3 Comments
Claas
Claas on 27 Mar 2019
Thanks for the fast response!
Let me give you following example:
A(:,:,1) =
1 2 3
4 5 6
7 8 9
A(:,:,2) =
21 22 23
24 25 26
27 28 29
A(:,:,3) =
31 32 33
34 35 36
37 38 39
Simple reshape results in sidewise "appending":
B=reshape(A,[3,9])
B =
1 2 3 21 22 23 31 32 33
4 5 6 24 25 26 34 35 36
7 8 9 27 28 29 37 38 39
you can state that since I want to reduce dimensions along the "z-axis", I need to permute first:
C=permute(A,[1 3 2]);
C2=reshape(C,[3,9])
C2 =
1 21 31 2 22 32 3 23 33
4 24 34 5 25 35 6 26 36
7 27 37 8 28 38 9 29 39
What I would like to get is:
desired=
32 31 21 1 2 3 23 22 33
35 34 24 4 5 6 26 25 36
38 37 27 7 8 9 29 28 39
I hope that made my problem a bit clearer...
Adam Danz
Adam Danz on 27 Mar 2019
Looks like you've got several solutions below.
Stephen Cobeldick's is quickest.
Andrei Bobrov's is most general (for example, if your array becomes 4x4x3).
Accept whichever answer suits your needs.

Sign in to comment.

Answers (5)

Andrei Bobrov
Andrei Bobrov on 27 Mar 2019
Edited: Andrei Bobrov on 27 Mar 2019
[m,n,k] = size(A);
B = ones(k,n);
[y,x] = find(B);
DT = delaunayTriangulation(x,y);
C = convexHull(DT);
[yy,xx] = ind2sub([k,n],circshift(C(1:end-1),ceil((numel(C) - n -1)/2)));
out = A(sub2ind([m,n,k],ones(numel(xx),1),xx,yy)' + (0:m-1)');
Another variant:
[m,n,k] = size(A);
B = ones(k,n);
[y,x] = find(B);
DT = delaunayTriangulation(x,y);
C = convexHull(DT);
D = reshape(permute(A,[1,3,2]),m,[]);
out = D(:,circshift(C(1:end-1),-floor((numel(C)-1)/2)-1));
  3 Comments
Stephen23
Stephen23 on 27 Mar 2019
Edited: Stephen23 on 27 Mar 2019
"This one matches the desired output."
??? My answer also gives exactly the requested output.
As Claas has not given any explanation of how this "unwrapping" should occur for other array sizes, your statement that Andrei Bobrov's solution is "the most general" is pure guessing: the order for larger array sizes has not been specified by Claas!
Adam Danz
Adam Danz on 27 Mar 2019
Edited: Adam Danz on 27 Mar 2019
Andrei initially had two answers and the second one did not match the desired output but this one did. I mentioned in the comments under the question, both yours and Andrei's match the desired outputs for the given inputs.

Sign in to comment.


Walter Roberson
Walter Roberson on 26 Mar 2019
Create a meshgrid of X, Y, Z coordinates relative to the center of the matrix. cart2pol() will then convert to r, theta, z .
Now create an interpolation grid of regularly spaced target r, target theta, target z coordinates, and
output = griddata(r, theta, z, OriginalMatrix, target_r, target_theta, target_z);

Stephen23
Stephen23 on 27 Mar 2019
Edited: Stephen23 on 27 Mar 2019
Currently the simplest solution is to just use indexing to get the order you want:
>> M = reshape(A,3,[]);
>> M = M(:,[8,7,4,1,2,3,6,5,9])
M =
32 31 21 1 2 3 23 22 33
35 34 24 4 5 6 26 25 36
38 37 27 7 8 9 29 28 39
There are multiple possible paths (especially the order of the last two columns seems quite arbitrary), and your definition is not enough to to define a general solution (e.g. consider an array with four columns and four pages: the outer "cylinder" might be intuitively defined, but the order of the inside columns is arbitrary, and you have not specified this).

Andrei Bobrov
Andrei Bobrov on 28 Mar 2019
Third variant :
A = reshape(1:9,3,[])' + cat(3,0,20,30);
[m,n,k] = size(A);
size_2_3 = [n,k];
xy0 = [2,3];
out = A(:,FunBoundary(size_2_3,xy0,'right'));
function out = FunBoundary(size_2_3,xy0,direction)
nk = prod(size_2_3);
n = size_2_3(1);
c = [1:n,2*n:n:nk,nk-1:-1:nk-n+1,nk-2*n+1:-n:n+1]';
if strcmp(direction,'left')
c = c(end:-1:1);
end
ii0 = xy0(1) + n*(xy0(2) - 1);
[~,ii] = ismember(ii0,c);
out = circshift(c,1-ii);
end

Claas
Claas on 17 Apr 2019
Hi,
sorry for the late response, but all of a sudden my other wokr piled up exponentially!
I haven't selected an answer due to the following reasons:
  • The first two variants of Andrei's proposal lead to information loss. Applying them to my actual scenario gives me 512x1178 matrix with all zeros (most of my data points are zero)
  • Stephen's works nice for small matrices, but doing it for 512x512x79.....
  • I still need to test Walter's answer and Andrei's third variant
Thanks again for the help.
Maybe for your interest: I try to implement something like this: https://www.tandfonline.com/doi/pdf/10.1080/0284186X.2017.1370130

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!