How can I split a matrix into N different parts?

62 vues (au cours des 30 derniers jours)
matlabkid602
matlabkid602 le 20 Juil 2017
Commenté : Jan le 17 Jan 2018
I have a 120x30 matrix of data points, how can I split the matrix into nine equal parts of 400 data chunks and store them as separate matrices?
  2 commentaires
Stephen23
Stephen23 le 20 Juil 2017
Modifié(e) : Stephen23 le 20 Juil 2017
"how can I split the matrix into nine equal parts of 400 data chunks and store them as separate matrices?"
While this is possible it would make your code slow, buggy, inefficient, hard to read, hard to debug, etc, etc. Here is what the MATLAB documentation says about magically creating variable names like that: "A frequent use of the eval function is to create sets of variables such as A1, A2, ..., An, but this approach does not use the array processing power of MATLAB and is not recommended. The preferred method is to store related data in a single array."
As you can read, the much better alternative is use one array and indexing. Indexing is simple, very efficient, neat, easy to read, easy to debug, etc, etc.
You can read more explanations and discussions here:
Just use indexing: simple, efficient, neat, easy to debug, easy to understand,... Or you could split the array into a cell array of numeric arrays: see mat2cell and num2cell.
Stephen23
Stephen23 le 24 Juil 2017
Modifié(e) : Stephen23 le 24 Juil 2017
Note to browsers of this thread: If you want to write fast, neat, efficient, and robust code then scroll down to Jan Simon's answer. It is not required to use slow and buggy code to solve this task.

Connectez-vous pour commenter.

Réponse acceptée

John BG
John BG le 20 Juil 2017
Modifié(e) : John BG le 20 Juil 2017
Hi matlabkid602
to split 120x30 matrix into chunks of 400 pixels, there are many different ways, like for instance selecting 400 random points and removing the just selected points from the matrix iterating until no points left, or using masks or patterns for similar elimination.
One can also sequentially pull strings of 400 pixels at a time, like Jan has concisely shown above, with a resulting cell.
For rectangular matrices, it is reasonable to aim at splitting the matrix into smaller rectangle chunks.
The following splits your 3600 points matrix into sub-rectangles of 400 points each
1.
loading example matrix
clear all;clc;close all
A=imread('001.jpg');
imshow(A)
2.
Scaling down to 120x30 pixels
the rulers are in pixels
.
.
3.
Simplifying to single RGB layer, made available in attached image 003.jpg
A=imread('003.jpg')
A=A(:,:,1);
fh=figure(1);imshow(A);ax=gca
fh.MenuBar='none'
fh.ToolBar='none'
fh.Position=[500 500 1440 360]
ax.OuterPosition=[0 0 1 1]
.
3.
Finding out how many rectangle chunks have 400 pixels area
L1=120 % x, horizontal
L2=30 % y, vertical
A0=400 % target area
K=L1*L2/A0 % how many equal area chunks, K is your N
x=[1:10]
y=[1:10]
[X,Y]=meshgrid(x,y)
L=(L1./X).*(L2./Y);
figure(4);S=surf(L)
.
N1=find(S.ZData==A0)'
% N1 =
% 9 23 81
It turns out vertical and horizontal slicing may also be possible
L(N1)
% =
% 400 400 400
% the slicing
a=X(N1)
% =
% 1 3 9
b=Y(N1)
% =
% 9 3 1
But since it's reasonable to assume that data points cannot be split, for the case pixels, the horizontal and vertical slicing cases a=1 b=9, a=9 a=1 have to be excluded.
Choosing the elements that are neither 1 or K
a=3;b=3
4.
Generating variable containing the rectangles
La=[1:L1/a:L1];
Lb=[L2:L2/b:L2];
D=zeros(L2/b,L1/a,K);
s=1
for j=1:1:b
for i=1:1:a
n2=[(j-1)*L2/b+[1:1:L2/b]]
n1=[(i-1)*L1/a+[1:1:L1/a]]
D(:,:,b*(j-1)+i)=A(n2,n1);
end
end
D=uint8(D) % for imshow to work correctly
close all;
for s=1:1:K
figure(s);imshow(D(:,:,s));
fh=figure(s);imshow(D(:,:,s));ax=gca
fh.MenuBar='none'
fh.ToolBar='none'
fh.Position=[500 500 480 120]
ax.OuterPosition=[0 0 1 1]
end
fh=figure(10)
for s=1:1:K
subplot(b,a,s);imshow(D(:,:,s))
end
.
5.
Dynamic generation of variables
Some people like the dynamic generation of variables with for instance command e evalin, some other people don't like such approach.
evalin is a very powerful command and I am using it here to generate the separate matrices you have asked for
.
str1=repmat('Chunk_',K,1) % building strings for evalin
N0=num2str(100+[1:1:K]');N0(:,1)=[]
N1=repmat('=D(:,:,',K,1)
N2=repmat(')',K,1)
str2=[str1 N0 N1 num2str([1:1:K]') N2]
for s=1:1:K % running evalin
L2=str2(s,:);
evalin('base',L2);
end
.
Now you have a list of smaller matrices containing the rectangular chunks
Chunk_01
Chunk_02
Chunk_03
Chunk_04
Chunk_05
Chunk_06
Chunk_07
Chunk_08
Chunk_09
if you find this answer useful would you please be so kind to consider marking my answer as Accepted Answer?
To any other reader, if you find this answer useful please consider clicking on the thumbs-up vote link
thanks in advance
John BG
  1 commentaire
Jan
Jan le 22 Juil 2017
Modifié(e) : Jan le 22 Juil 2017
The shown code works in the command window only, because evalin('base') creates the variables in the Base-WorkSpace. Hundreds of threads in this forum explain the drawbacks of the dynamic creation of variables exhaustively. See Stephen's comment above.

Connectez-vous pour commenter.

Plus de réponses (2)

Jan
Jan le 20 Juil 2017
Modifié(e) : Jan le 22 Juil 2017
Storing in separate matrices might be a bad idea. Why not using the matrix itself?
data = rand(120, 30);
data9 = reshape(data, [], 9);
dataC = cell(1, 9);
for iC = 1:9
dataC{iC} = data9(:, iC);
end
Here you get the different vectors as a cell array. But I'd prefer to work with data9: The i.th block is data9(:, i).
[EDITED] You can split the matrix to a 3x3 set uf submatrices efficiently without nested loops by:
sM = size(M);
c = reshape(M, sM(1) / 3, 3, sM(2) / 3, 3);
M33 = permute(reshape(c, 4, 3, 3, 3), [1, 3, 2, 4]);
M9 = reshape(M33, [4, 3, 9]);
Now the matrix is divived in 3 x 3 submatrices of the same size, which can be addressed by M9(:, :, i) with the index 1 to 9 or by using M33(:, :, x, y) with x and y going from 1 to 3.
This is much faster then nested loops.
  2 commentaires
Kodavati Mahendra
Kodavati Mahendra le 17 Jan 2018
Modifié(e) : Kodavati Mahendra le 17 Jan 2018
regarding the edit you made, c has more than 4*3*3*3 elements.
sM = size(M);
M33 = permute(reshape(M,sM(1)/3,3,sM(2)/3,3),[1,3,2,4]);
M9 = reshape(M33, [sM(1)/3,sM(2)/3,9]);
Is this the correct code or did I misunderstand it?
Jan
Jan le 17 Jan 2018
@Kodavati Mahendra: This looks fine.

Connectez-vous pour commenter.


Image Analyst
Image Analyst le 22 Juil 2017
You didn't specify how you wanted the matrix split up, since neither 120 nor 30 is a multiple of 9. So I just made 9 vectors taking the data column by column from upper left to lower right. Try this:
data = rand(120,30); % Sample data
% Now split up into 9 row vectors.
m1 = data(1:1*400);
m2 = data(1*400+1 : 2*400);
m3 = data(2*400+1 : 3*400);
m4 = data(3*400+1 : 4*400);
m5 = data(4*400+1 : 5*400);
m6 = data(5*400+1 : 6*400);
m7 = data(6*400+1 : 7*400);
m8 = data(7*400+1 : 8*400);
m9 = data(8*400+1 : 9*400);
If those aren't the 9 arrays you were thinking of them clarify the location of where the elements for each matrix are supposed to come from.

Catégories

En savoir plus sur Variables dans Help Center et File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by