approach to save and load a 3D matrix - matlab

I need to save a 3D matrix in a text file that will be loaded in Matlab (which I don't master). My first idea was to do it with a .csv like this, (consider a 3x3x3 matrix):
row 1: v[0][0][0],v[0][0][1] ,v[0][0][2]
row 2: v[0][1][0],v[0][1][1] ,v[0][1][2]
row 3: v[0][2][0],v[0][2][1] ,v[0][2][2]
row4: v[1][0][0],v[1][0][1] ,v[1][0][2]
...
Like this, I must inform the user separately about the number of x an y dimensions. Not too clean, but not a big drama.
My question is, how could I load and plot in Matlab a dataset like this? Values are 1/0.
Is there any smarter way of doing this. I am exporting from Java.
Thanks!

I can't think of a way that you can omit storing the dimensions of the matrix (at least two of them should be mentioned). But when it comes to storing values in a file, I suggest that you do not bother to even write them in tabular format. All you need to know about MATLAB is the order of elements in a matrix. Take a look at this example:
%% create a 3d matrix
% a = 1+randi(5);
% b = 1+randi(5);
% c = 1+randi(5);
a = 2; b = 3; c = 4;
M = reshape(1:a*b*c, a, b, c)
This is how the matrix looks like:
M(:,:,1) =
1 3 5
2 4 6
M(:,:,2) =
7 9 11
8 10 12
M(:,:,3) =
13 15 17
14 16 18
M(:,:,4) =
19 21 23
20 22 24
Now let's write it in a text file:
%% writing matrix in the text file,
% translate it to your target language
fid = fopen('matrix.txt', 'w');
fprintf(fid, '%d,%d,%d\n', a, b, c);
for k=1:c
for j=1:b
for i=1:a
fprintf(fid, '%-.8g\n', M(i, j, k));
end
end
end
fclose(fid);
This is the contents of the file:
2,3,4
1
2
3
4
...
21
22
23
24
Now, to read the file:
%% read the file back in MATLAB
fid = fopen('matrix.txt', 'r');
sz = str2num(fscanf(fid, '%s\n', 1)); % read dimensions
M2 = reshape(fscanf(fid, '%f\n', inf), sz); % read values
fclose(fid);
%% test the imported matrix
disp(sz)
if all(all(all(M == M2)))
disp('OK')
else
disp('Test failed.')
end

Related

Matlab from text file to sparse matrix.

I have a huge text file in the following format:
1 2
1 3
1 10
1 11
1 20
1 376
1 665255
2 4
2 126
2 134
2 242
2 247
First column is the x coordinate while second column is the y coordinate.
It indicates that if I had to construct a Matrix
M = zeros(N, N);
M(1, 2) = 1;
M(1, 3) = 1;
.
.
M(2, 247) = 1;
This text file is huge and can't be brought to main memory at once. I must read it line by line. And save it in a sparse matrix.
So I need the following function:
function mat = generate( path )
fid = fopen(path);
tline = fgetl(fid);
% initialize an empty sparse matrix. (I know I assigned Mat(1, 1) = 1)
mat = sparse(1);
while ischar(tline)
tline = fgetl(fid);
if ischar(tline)
C = strsplit(tline);
end
mat(C{1}, C{2}) = 1;
end
fclose(fid);
end
But unfortunately besides the first row it just puts trash in my sparse mat.
Demo:
1 7
1 9
2 4
2 9
If I print the sparse mat I get:
(1,1) 1
(50,52) 1
(49,57) 1
(50,57) 1
Any suggestions ?
Fixing what you have...
Your problem is that C is a cell array of characters, not numbers. You need to convert the strings you read from the file into integer values. Instead of strsplit you can use functions like str2num and str2double. Since tline is a space-delimited character array of integers in this case, str2num is the easiest to use to compute C:
C = str2num(tline);
Then you just index C like an array instead of a cell array:
mat(C(1), C(2)) = 1;
Extra tidbit: If you were wondering how your demo code still worked even though C contained characters, it's because MATLAB has a tendency to automatically convert variables to the correct type for certain operations. In this case, the characters were converted to their double ASCII code equivalents: '1' became 49, '2' became 50, etc. Then it used these as indices into mat.
A simpler alternative...
You don't even have to bother with all that mess above, since you can replace your entire function with a much simpler approach using dlmread and sparse like so:
data = dlmread(filePath);
mat = sparse(data(:, 1), data(:, 2), 1);
clear data; % Save yourself some memory if you don't need it any more

A is a mXn matrix, ind is a jX1 If i query v=a(id(j),:) why Matlab give me v=a(id(j+1),:)?

I have a file that contain the data logged of 6 experiments with this information logged "time ax ay az gx gy gz"
I will call it logmpu6050 in my specific case a 26,220X7 matrix.
I can recognize every experiment because time restart from a lower random value from the previous.
So when this condition is satisfied ti>ti+1 the data of the following experiment starts from the i+1 row.
I defined a "boundary vector" "ind" that contains all this value, and i added the first (1,1) and the last value(end,1) of the first column of the logmpu6050 matrix because are two exeption that don't satisfy the condition.
But when i want to know for example, this information:
query1=logmpu6050(ind(1),:)
Matlab gave me the values of the second row of ind, not the first, as you can see in the pic attached. Why?
I also tought it could start counting from 0, but is false, Matlab dispalys an error message with the 0 value.
Thanks, always, for your time, my civil engineer background makes hard to solve this kind of problems.
Here the code i wrote.
%Open the file
filename= uigetfile ('.txt');
fileID = fopen (filename);
logmpu6050 =csvread(filename);
fclose (fileID);
n=length(logmpu6050);
%Count every time i>i+1 and store the entire raw value
ind=find(diff(logmpu6050(:,1))<0);
ind=[logmpu6050(1,1);ind(:,:);logmpu6050(end,1)];
%No errors appear - logmpu6050 is a 26220X7 double - ind is a 7x1
ind
query1=logmpu6050(ind(1),:)
query2=logmpu6050(ind(2),:)
An alternative method could split the matrix into a cell array of submatrices:
% Generate an example
N = 3; % Num of experiments
n = randi([2,5],N,1); % Points per experiment
logmpu6050 = cell2mat(arrayfun(#(x) [(1:n(x))' x*ones(n(x),6)],1:N,'UniformOutput',0)');
% Find cut points
cuts = [diff(logmpu6050(:,1))<0;1];
% Split into a cell array
experiments = mat2cell(logmpu6050,diff([0;find(cuts)]));
Then you can access the submatrices like:
% The first experiment
experiments{1}
% The second experiment
experiments{2}
I think a lookup function would work nicely to pull out the submatrices you want.
Here's an example
% Generate an example data matrix
n = 3; % Points per experiment
N = 3; % Num of experiments
logmpu6050 = [repmat((1:n),1,N); repmat((1:n*N),6,1)]';
% Make a lookup function
lookup = #(x) cumsum([1;diff(logmpu6050(:,1))<0])==x;
% Get experiment 1 data
logmpu6050(lookup(1),:)
% Get experiment 2 data
logmpu6050(lookup(2),:)
This will output for the first experiment:
ans =
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 3 3 3 3 3 3
and for the second:
ans =
1 4 4 4 4 4 4
2 5 5 5 5 5 5
3 6 6 6 6 6 6

Matlab random sampling

I am trying to exercise myself in Matlab. I am trying to select randomly two lines from a file named data.dat.
My data.dat file looks like this:
12 4 6.1 7
14 4 8.4 62
7 56.1 75 98
9.7 54 12 35
2 4 8 7.8
To select 2 lines randomly from the data.dat here is how I am proceeding:
close all;
clear all;
%----------------------%
% Choose random lines
%----------------------%
M = load('data.dat');
N=2; %number_of_lines
file_number = 2; %save each two lines in new file: selection_1, selection_2
Now I am saving the two selected lines in new files sequentially.
for k = 1:file_number
i = randi(length(M),N);
B=M(i,:)
filename=['samples_',int2str(k),'_mc.dat']
save (filename, 'B', '-ascii')
clear B;
end
I don't know why but I have more than 2 lines in each new files. Could you please explain me where did I made a mistake.
I think you are making a mistaking when you generate the random numbers, as indicated by GameOfThrows.
i = randi(length(M),N); % gives you a matrix NxN of numbers
i = randi(length(M),[N,1]); % gives you a column of N numbers

save text file matlab

Another question on fprintf
I have a matrix s(n,5) that I want to shorten (just take columns 3,4 and 5) into s1(n,3) and save with a different name.
s1=s(:,3:5);
txtfilename = [Filename '-1.txt'];
% Open a file for writing
fid = fopen(txtfilename, 'w');
% print values in column order
% two values appear on each row of the file
fprintf(fid, '%f %f %f\n', s1);
fclose(fid);
I don't think I understood the way to use fprintf and rewrite my new matrix, because it is sorting the values.
Thanks for your help
The problem is that MATLAB stores data in column-major order, meaning that when you do s1(:), the first three values are the first three values in the first column not the first row. (This is how fprintf will read values out of s1.) For example:
>> M = magic(3)
M =
8 1 6
3 5 7
4 9 2
>> M(:)
ans =
8
3
4
1
5
9
6
7
2
You can simply transpose the matrix to output the way you want:
fprintf(fid, '%f %f %f\n', s1.');

extract every n row in a matrix to another matrix in a loop

I'm a total beginner to matlab and I'm currently writing a script for extracting data from a thermographic video.
Firstly the video is cut in separate frames. The first frame is opened as a sample picture to define the coordinates of sampling points. The goal is then to select the rgb values of those defined coordinates from a set of frames and save them into a matrix.
Now I have a problem separating the matrix to n smaller matrices.
e.g I'm defining the number of points to be selected to n=2 , with a picture count of 31. Now it returns a matrix stating the rgb codes for 31 pictures, each at 2 points, in a 62x3 double matrix...
Now I want to extract the 1st, 3rd, 5th....etc... row to a new matrix...this should be done in a loop, according to the number of n points...e.g 5 points on each picture equals 5 matrices, containing values of 31 pictures....
this is an extract of my code to analyse the pictures, it returns the matrix 'values'
files = dir('*.jpg');
num_files = numel(files);
images = cell(1, num_files);
cal=imread(files(1).name);
n = input('number of selection points?: ');
imshow(cal);
[x,y] = ginput(n);
eval(get(1,'CloseRequestFcn'))
%# x = input('x-value?: '); manual x selection
%# y = input('y-value?: '); manual y selection
for k = 1:num_files
images{k} = imread(files(k).name);
end
matrix=cell2mat(images);
count=(0:size(matrix,1):size(matrix,1)*num_files);
for k = 1:num_files
a(k)= mat2cell(impixel(matrix,x+count(k),y));
end
values = cat(1,a{:})
Easy fix
Do you mean that if you have:
n = 2;
k = 2; % for example
matrix = [1 2 3;
4 5 6;
7 8 9;
8 7 6];
you want it to become
b{1} = [1 2 3;
7 8 9];
b{2} = [4 5 6;
8 7 6];
This can be easily done with:
for ii = 1:n
b{ii} = matrix(1:n:end,:);
end
Better fix
Of course it's also possible to just reshape your data matrix and use that instead of the smaller matrices: (continuing with my sample data ^^)
>> d=reshape(matrix',3,2,[]);
>> squeeze(d(:,1,:))
ans =
1 7
2 8
3 9
>> squeeze(d(:,2,:))
ans =
4 8
5 7
6 6
Good practice
Or, my preferred choice: save the data immediately in an easy to access way. Here I think it will be an matrix of size: [num_files x num_points x 3]
If you want all the first points:
rgb_data(:,1,:)
only the red channel of those points:
rgb_data(:,1,1)
and so on.
I think this is possible with this:
rgb_data = zeros(num_files, num_points, 3);
for kk = 1:num_files
rgb_data(kk,:,:) = impixel(images{kk},x+count(k),y);
end
But I don't understand the complete meaning of your code (eg: why matrix=cell2mat(images) ??? and then of course:
count=(0:size(matrix,1):size(matrix,1)*num_files);
is just count=0:num_files;
so I'm not sure what would come out of impixel(matrix,x+count(k),y) and I used images{k} :)