How to calculate per-page STD in matlab? - matlab

Suppose I have matrix A of 100x200x300. Third dimension is called "page" in Matlab and this matrix has 300 pages then.
Now I want to calculate standard deviation within each page and get a result matrix of 1x1x300.
I can't just do
std(std(A,0,1),0,2)
because normalization will be wrong as I think.

You need to collapse the first two dimensions into one (i.e. into columns) using reshape; and then compute std along each column:
Ar = reshape(A, size(A,1)*size(A,2), size(A,3));
result = std(Ar);
This will give you a 1x300 vector as result. If you really need it to be 1x1x300, use
result = shiftdim(result, -1);

Related

Difference in Matlab results when using PCA() and PCACOV()

Closest match I can get is to run:
data=rand(100,10); % data set
[W,pc] = pca(cov(data));
then don't demean
data2=data
[W2, EvalueMatrix2] = eig(cov(data2));
[W3, EvalueMatrix3] = svd(cov(data2));
In this case W2 and W3 agree and W is the transpose of them?
Still not clear why W should be the transpose of the other two?
As an extra check I use pcacov:
[W4, EvalueMatrix4] = pcacov(cov(data2));
Again it agrees with WE and W3 but is the transpose of W?
The results are different because you're subtracting the mean of each row of the data matrix. Based on the way you're computing things, rows of the data matrix correspond to data points and columns correspond to dimensions (this is how the pca() function works too). With this setup, you should subtract the mean from each column, not row. This corresponds to 'centering' the data; the mean along each dimension is set to zero. Once you do this, results should be equivalent to pca(), up to sign flips.
Edit to address edited question:
Centering issue looks ok now. When you run the eigenvalue decomposition on the covariance matrix, remember to sort the eigenvectors in order of descending eigenvalues. This should match the output of pcacov(). When calling pca(), you have to pass it the data matrix, not the covariance matrix.

Position of median blocks

I have a problem in matrix (A) 9*9, I need to extract median for each block 3*3.
Also, I need to know the position of the median in each block.
Note:
I know how can extract the median by using
m=median(median(B));
and B is block in matrix
B = A(i:i+L-1, j:j+L-1);
thank you.
If you have the image processing toolbox installed you can use:
medianBlocks = blockproc(A,[3,3],#(X) ones(size(X.data))*median(X.data(:)))
A == medianBlocks
If you don't have the Image Processing Toolbox, I suggest transforming each neighbourhood so that it fits into a single column then you stack all of these columns together to create a single matrix. Once you have this new matrix, find the median of each column, then use this result for further processing.
The best way to do this would be to use im2col to create this temporary matrix and do the median on this matrix over the columns. The output will give you the median of each neighbourhood in your image.
Ironically, im2col is part of the Image Processing Toolbox. However, Divakar has made a vectorized and more efficient version of it that doesn't require the toolbox and only relies on native MATLAB commands.
See here: Efficient Implementation of `im2col` and `col2im`
As such, depending on whether you want overlapping blocks or sliding blocks, use whichever command suits you. Therefore:
out = im2col_distinct(A, [3 3]); %//OR
%out = im2col_sliding(A, [3 3]);
out_median = median(out);
out_median will contain a vector that has the median of each block in the image. Now, if you want to find which location in each window has the median, you can make a bsxfun call:
loc = bsxfun(#eq, out, out_median);
loc will contain the column-major locations of each block. If you want the row and column locations with respect to each block, you can use ind2sub:
[rows,cols] = ind2sub([3 3], loc);
rows and cols will give you the row and column locations of where the median was located in each block neighbourhood of your image.

Slicing Power Spectral Density over frequency bands

I am using pwelch to get the Power Spectral Density of multiple signal vectors and then finding the average signal to noise ratios over 5 frequency bands.
I converted the power spectral densities to dB and am currently obtaining each band one by one:
P_signal1(band1)
P_signal1(band2)
P_signal1(band3)
...
P_signal2(band1)
P_signal2(band2)
and so on.
Is there any way to obtain this easily, maybe using arrays of the signals and the bands
signals = [P_signal1, P_signal2, P_signal3, P_signal4, P_signal5]
bands = [band1, band2, band3, band4, band5]
and obtain a matrix of each combination?
A = 1:100;
bands = [1:20;21:40;41:60;61:80;81:100];
A(bands)
Full documentation can be seen here.
The idea is indexing in Matlab is a lot different than in other languages, since Matlab uses matrices. When you index an array like A(1), it will pick one element out, just like any other language. When you index it as A([2,1;3,1]), magic happens. Matlab will take out elements of A 4 times, each corresponding to one element in [2,1;3,1]. And then it arranges the 4 results in the same form of [2,1;3,1]. The output will be also a matrix.
EDIT: Using cell array
A = 1:100;
bands = {1:20;21:40;41:60;61:80;81:100};
cell2mat( cellfun(#(x) A(x), bands, 'UniformOutput', false) )
This works differently than above, but shares similar idea. Now bands is a cell array, each element containing an index range.
cellfun takes each of this range as x, and evaluate expression A(x) (which means access that part of A), and put the result into a new cell array, of which the size is same with bands, and the element position accords to the definition in bands.
cell2mat converts this output cell array into a plain numeric array.

Selecting values plotted on a scatter3 plot

I have a 3d matrix of 100x100x100. Each point of that matrix has assigned a value that corresponds to a certain signal strength. If I plot all the points the result is incomprehensible and requires horsepower to compute, due to the large amount of points that are painted.
The next picture examplify the problem (in that case the matrix was 50x50x50 for reducing the computation time):
[x,y,z] = meshgrid(1:50,1:50,1:50);
scatter3(x(:),y(:),z(:),5,strength(:),'filled')
I would like to plot only the highest values (for example, the top 10). How can I do it?
One simple solution that came up in my mind is to asign "nan" to the values higher than the treshold.
Even the results are nice I think that it must be a most elegant solution to fix it.
Reshape it into an nx1 vector. Sort that vector and take the first ten values.
num_of_rows = size(M,1)
V = reshape(M,num_of_rows,1);
sorted_V = sort(V,'descend');
ind = sorted_V(1:10)
I am assuming that M is your 3D matrix. This will give you your top ten values in your matrix and the respective index. The you can use ind2sub() to get the x,y,z.

Matlab code to compare two histograms

I want to compare two image histograms. They are as follows:
h1 --> double valued 1 dimension vector .4096 in length.
h2 --> double valued 1 dimension vector .4096 in length.
I am using this matlab function here:
http://clickdamage.com/sourcecode/code/compareHists.m
It is as follows:
% s = compareHists(h1,h2)
% returns a histogram similarity in the range 0..1
%
% Compares 2 normalised histograms using the Bhattacharyya coefficient.
% Assumes that sum(h1) == sum(h2) == 1
%
function s = compareHists(h1,h2)
s = sum(sum(sum(sqrt(h1).*sqrt(h2))));
My question is :
Is there a need for multiple sums?
Even if there is only one sum in the above equation, it would suffice..right?
like this: sum(sqrt(h1).*sqrt(h2)) --> ?
Can some one please explain the code above? Also, tell me if I use a single sum will it be all right?
I tried both ways and got the same answer for two image histograms. I did this with only two histograms not more and hence want to be sure.
Thanks!
In general, sum does the sum along one dimension only. If you want to sum along multiple dimensions you either
use sum several times; or
use linear indexing to reduce to a single dimension and then use sum once: sum(sqrt(h1(:)).*sqrt(h2(:))).
In your case, if there's only one dimension, yes, a single sum would suffice.
You are right. Only one sum is needed. However, if either h1 or h2 is a multidimensional matrix, then you may want to sum as many as the dimensions. For example:
A=magic(4); % a 4 by 4 matrix of magic numbers.
sum(A) % returns [34,34,34,34], i.e. the sum of elements in each column.
sum(sum(A)) % returns 136, i.e. the sum of all elements in A.
I believe the code you downloaded originaly was written to handle multiple histograms stacked as columns of a matrix. This is (IMHO) the reason for the multiple sums.
In your case you can leave it with only one sum.
You can do even better - without any sum
Hover here to see the answer
s = sqrt(h1(:)')*sqrt(h2(:));
The trick is to use vector multiplication!
I don't see any points in 3 sums too, but if you have not a vector with histogram but a matrix you will need 2 sums like this sum(sum(sqrt(h1).*sqrt(h2))) to compare them. First one will calculate the sum of the rows, the second - the sum of the columns.