peak finder for multidimensional array - matlab

I'm trying the following and is not working. Could someone help me on this?
A=rand(1,4,5);
peak_num=zeros(5,4);
for w=1:5
peak_num(w,:)=peakfinder(A(1,1:4,w))
end
peak_num;
in this case the vector of peaks found for each w has a different size.
Thanks

I haven't really taken a look at the internals of the peakfinder function but if you make sure that it does not output a vector with more than 4 elements this is a workaround:
A=rand(1,4,5);
peak_num=zeros(5,4);
for w=1:5
temp = peakfinder(A(1,1:4,w));
peak_num(w, 1:length(temp) ) = temp
end
peak_num;
It sets the first elements to the return values and keeps the others being zero.

Related

Applying (with as few loops as possible) a function to given elements/voxels (x,y,z) taken from subfields of multiple structs (nifti's) in MATLAB?

I have a dataset of n nifti (.nii) images. Ideally, I'd like to be able to get the value of the same voxel/element from each image, and apply a function to the n data points. I'd like to do this for each voxel/element across the whole image, so that I can reconvert the result back into .nii format.
I've used the Tools for NIfTI and ANALYZE image toolbox to load my images:
data(1)=load_nii('C:\file1.nii');
data(2)=load_nii('C:\file2.nii');
...
data(n)=load_nii('C:\filen.nii');
From which I obtain a struct object with each sub-field containing one loaded nifti. Each of these has a subfield 'img' corresponding to the image data I want to work on. The problem comes from trying to select a given xyz within each img field of data(1) to data(n). As I discovered, it isn't possible to select in this way:
data(:).img(x,y,z)
or
data(1:n).img(x,y,z)
because matlab doesn't support it. The contents of the first brackets have to be scalar for the call to work. The solution from googling around seems to be a loop that creates a temporary variable:
for z = 1:nz
for x = 1:nx
for y = 1:ny
for i=1:n;
points(i)=data(i).img(x,y,z);
end
[p1(x,y,z,:),~,p2(x,y,z)] = fit_data(a,points,b);
end
end
end
which works, but takes too long (several days) for a single set of images given the size of nx, ny, nz (several hundred each).
I've been looking for a solution to speed up the code, which I believe depends on removing those loops by vectorisation, preselecting the img fields (via getfield ?)and concatenating them, and applying something like arrayfun/cellfun/structfun, but i'm frankly a bit lost on how to do it. I can only think of ways to pre-select which themselves require loops, which seems to defeat the purpose of the exercise (though a solution with fewer loops, or fewer nested loops at least, might do it), or fun into the same problem that calls like data(:).img(x,y,z) dont work. googling around again is throwing up ways to select and concatenate fields within a struct, or a given field across multiple structs. But I can't find anything for my problem: select an element from a non-scalar sub-field in a sub-struct of a struct object (with the minimum of loops). Finally I need the output to be in the form of a matrix that the toolbox above can turn back into a nifti.
Any and all suggestions, clues, hints and help greatly appreciated!
You can concatenate images as a 4D array and use linear indexes to speed up calculations:
img = cat(4,data.img);
p1 = zeros(nx,ny,nz,n);
p2 = zeros(nx,ny,nz);
sz = ny*nx*nz;
for k = 1 : sz
points = img(k:sz:end);
[p1(k:sz:end),~,p2(k)] = fit_data(a,points,b);
end

(simple?) error with findpeaks and if loop

I'm trying to find the local maxima of a data set using the findpeaks() function and so far I have this code:
[pks, locs] = findpeaks(signal);
max_times = zeros(size(locs));
if n = 1:size(locs);
max_times(n) = (times(locs(n)));
end
What am I trying to do? Well I have a set of signal data and the corresponding times. I want to get the local maxima values and output two vectors; the maxima signal values and the times that they occured.
How am I doing it? I'm using the findpeaks function to find the peaks (pks) and location (locs) of the maxima. I'm then setting up a blank array the same length as the locs vector and then using an if loop to fill up the empty max_times(n) vector with the times that the maxima occur
The problem? I keep getting this errorExpression or statement is incomplete or incorrect. about my if loop. I don't understand what this means/ how do I solve this problem/ edit my code to get it to do what I want?
Thanks for any help!
What you are thinking is totally wrong.
If is not a loop its a conditional statement
what you want here is a for loop
for n = 1:size(locs)
% your code
end
also times take two parameter and you should figure it out yourself what it should be

How to add elements to a vector in matlab

I've looked around on the internet a bit and cannot seem to find the answer to this question. I want to declare a vector in matlab and then have a for loop that will add an element to the vector each time I go through the for loop.
This is what I've tried and it doesn't seem to be working
vector[];
for k = 1 ; 10
%calculate some value
%calculated value stored in temp variable
vector(k) = temp;
end
This does not work. Does anybody know how to solve this issue?
As ypnos said, you don't need to declare the vector variable upfront. For example if you did:
vector(50) = 1;
MATLAB would make a vector of length 50 with the 50th value being 1. If you want to improve performance and want to create a vector of the proper size beforehand then do the following:
vector = zeros(10, 1);
The code as you have it (as long as you fix the loop as ypnos said) will work, except for how you declare vector, which is not correct. I bet you are getting the error message: "Error: Unbalanced or unexpected parenthesis or bracket." You do not specify whether a variable is a matrix/vector in MATLAB.
vector = [vector; temp];
or
vector(end+1) = temp;

Referring to coordinates of a 3d matrix in Matlab

In Matlab I'm trying to find points in a 3d matrix whose coordinates are smaller than some function.
If these coordinates are equal to some functions than I can write:
A(some_function1,some_function2,some_function3)=2;
But what if I want to do something like:
A(<some_function1,<some_function2,<some_function3)=2;
This isn't working - so what is the other way of finding such points without using "for" loop? Unfortunately with "for" loop my code takes a lot of time to compute. Thank you for your help!
How about something along the lines of
A( ceil(min(some_function1,size(A,1))),...
ceil(min(some_function2,size(A,2))),...
ceil(min(some_function3,size(A,3))) );
This will cap the indicies to the end of each array dimension
You can just use regular indexing to achieve this:
A(1:floor(some_function1),1:floor(some_function2),1:floor(some_function3)) = 2;
assuming you check / ensure that floor(some_function*) is smaller than the dimensions of A
Try:
A(1:size(A,1)<some_function1, 1:size(A,2)<some_function2, 1:size(A,3)<some_function3) = 2
I hope I got your question correctly.

what function or loop do I have to use to average the matrix?

I want to find the average of all the matrix:
Data=(Data{1}+......+Data{n})/n)
where Data{n} is a matrix of m*n..
Thank you sooo much
First, you convert your cell array into a 3D array, then you can take the average, like this:
tmp = cat(3,Data{:}); %# catenates the data, so that it becomes a m*n*z (or m*1*n)
averageData = mean(tmp,3); %# takes average along 3rd dimension
Note: if you get memory problems this way, and if you don't need to keep the variable Data around, you can replace tmp with Data and all will work fine.
Alternatively, if Data is simply a m*n numeric array
averageData = mean(Data,2);
If your cell array is really big, you might want to keep away from the above solution because of its memory usage. I'd then suggest using the utility mtimesx which is available from Matlab Central, here.
N = length(Data);
b = cell(N,1);
b(:) = {1};
averageData = mtimesx(Data,b)/N;
In the above example, I assumed that Data is a line-shaped cell array. I have never used personally mtimesx, this solution comes from there, where timing issues are also discussed.
Hope this helps.
A.