trim auto-correlation result in MATLAB - matlab

I am using xcorr2(A,A) for computing the auto-correlation. But, the output is bigger than A. How I should trim the output to find the correct auto-correlation matrix? For example, my A matrix is 51x51 and the output will be 101x101. It is clear that the central point has the maximum correlation with itself which in this case is located in (26,26), but in the new auto-correlation map, it is located in (51,51). I need a general way to trim the final output.

In general you have to take M points from M/2 to 3M/2 in the 1st dimension, and N points from N/2 to 3N/2 in the 2nd dimension, assuming A is an M-by-N matrix:
[M, N] = size(A);
cor = xcorr2(A); %# Shorter form of xcorr(A, A)
C = cor(ceil(M / 2):floor(3 * M / 2), ceil(N / 2):floor(3 * N / 2))
Here C would be the trimmed output.
EDIT:
For any two matrices A and B, the result of xcorr2(A, B) would be a (MA+MB-1)×(NA+NB-1) matrix. Here, however, you'll have to decide for yourself which part you want to extract, if the matrices are not of equal dimensions. If you want to extract the significant central part, you can do it like so:
[MA, NA] = size(A);
[MB, NB] = size(B);
v = [MA + MB, NA + NB] / 4; %# Just a temporary vector
cor = xcorr2(A, B);
C = cor(ceil(v(1)):floor(3 * v(1)), ceil(v(2)):floor(3 * v(2))

Related

Using the SVD rather than covariance matrix to calculate eigenfaces

I'm using the set of n = 40 faces from AT&T (http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html) to try and generate eigenfaces via the SVD.
First I calculate the average vector:
Then I subtract it from every vector in the training set, reshape the new vector into a 1 by (p*q) column vector of a n by (p*q) matrix x, and calculate a matrix X such that X = (1/sqrt(n))*x. (here's where the issue is: all my results in X are rounded to 0, resulting in a black image result for eigenface as seen below)
Then I calculate the SVD of this matrix X and try to get the first eigenface of the first column of the unitary matrix by reshaping it back into a p by q matrix
However, this is my result:
Can anyone spot my error in the code below? Any answer is much appreciated
n = 40;
%read images
A = double(imread('faces_training/1.pgm'));
f(:, :, 1) = A;
for j = 2:n
f(:, :, j) = double(imread(['faces_training/',num2str(j),'.pgm']));
A = A + f(:, :, j);
end
%calculate average
a = (1/n)*A;
%imshow(uint8(a))
for i = 1:n
%subtract from images
x_vector(:, i) = reshape(f(:, :, i) - a, [], 1);
end
X = (1/sqrt(n))*x_vector;
%svd
[U S V] = svd(X);
B = reshape(U(:, 1), [size(a, 1) size(a, 2)]);
imshow(uint8(B))
Doing the same thing and had the same problem. The short answer is you have to normalize your eigenvector to get a good image. Before normalizing, you’ll notice your vector values are very close to 0 (probably because of how svd was done) which probably means they’re close to black.
Anyway, use this equation on the eigenvectors you wanna transform:
newpixel[i,j]=(oldpixel[i,j]-min(oldpixel[:,j]))/(max(oldpixel[:,j])--min(oldpixel[:,j]))

Linear combination of the Slices in a 3D

I have a 3D matrix sized (x,y,N) and a 2D matrix sized (N,N).
I would like to manipulate the two in a way that each column in the 2D matrix has the coefficients for a linear combination of the 2D sized- (x, y) slices in the 3D matrix. And I would like to do this for all N columns in the 2D matrix.
Schematically,
Currently the code looks like:
A = zeros(numel(x_axis), numel(y_axis), N);
B = zeros(numel(x_axis), numel(y_axis), N);
C = zeros(N, N)
for i = 1 : N
for j = 1 : N
A(:,:,i) = A(:,:,i) + B(:,:,j) * C(j,i);
end
end
But it is quite slow. Is there any way to speed up the MATLAB code by vectorizing?
If I understand your problem well, then this should work:
[p,q,N] = size(B);
A = reshape( reshape(B, [p*q, N]) * C, [p, q, N]);
edit: Cleaner version suggested by Suever:
A = reshape(reshape(B, [], size(B, 3)) * C, size(B))
Generalization to the R-D case:
A = reshape(reshape(B, [], size(B, ndims(B))) * C, size(B))
You can use bsxfun which will calculate this very quickly for you. We have to use permute to re-arrange C a little bit to ensure that it has conformant dimensions for using bsxfun and then we perform the summation along the third dimension of the resulting output and apply squeeze to remove the singleton third dimension.
A = squeeze(sum(bsxfun(#times, B, permute(C, [3 4 1 2])), 3))

Perform element wise multiplication of vectors efficiently?

I have to perform matrix updating by M = M + c*a*a' large number of times, where c is a constant and a is a column vector. If the size of matrix is larger than 1000, this simple updating will cost most of the time of my function, typically more than 1 min counted by profile.
Main codes are:
for i = 1:N
_do something..._
for k = 1:n
a(1:k) = M(1:k,1:k)*p(1:k);
M(1:k,1:k) = M(1:k,1:k)+c*a(1:k)*a(1:k)';
M(1:k, k+1) = b(1:k);
M(k+1, 1:k) = b(1:k)';
M(k+1, k+1) = x;
......
end
end
I have preallocated all variables, column vectors p and b are known, and x is another constant.
As I have large number of data to process by this function, does there exist more efficient alternative to this matrix updating?
You can concatenate a vectors to create a matrix A then apply multiplication just one time.
A =[a1 a2 a3];
M = c * A * A.';
consider the example
A = rand(5,5);
M = 0;
c=4;
for n = 1:5
M = M + c * A(:,n) * A(:,n).';
end
and this one
M1 = c * A * A.'
both M and M1 are equal
Have you tried using bsxfun?
In any case, bsxfun is much faster than regular multiplication, but the vectors/matrices have to be of equal length (which they are for you, aren't they?), and it's operating elementwise (i.e. a Nx1 vector bsx-multiplied with itself yields a Nx1 vector, multiplied with the transpose however yields a NxN matrix).
see https://mathworks.com/help/matlab/ref/bsxfun.html
use as
bsxfun(#times, a, a')

How to sum a sub-tensor of high dimention tensor in Matlab?

We are given a D-dimensional tensor, represented as a vector of size n^D.
The vector represents a D-dimensional distribution of a random variable X \in {0,1,..,n}^d. That is the (i_1,i_2,...,i_d) entry in the tensor represents the probability of X_1 = i_1, X_2 = i_2, ... X_d = i_d.
I need to compute, for each dimension d, and value i\in [n] the marginal distribution P(X_d = i).
i.e., this means that the answer of P(X_d = i) is the sum of n^(D-1) entries of the vector.
For example, if D=2 and n=4, we have a vector x of size (16,1) and the probability of the first dimension being equal to 1 is
P(X_1 = 1) = x(1) + x(2) + x(3) + x(4)
The probability of the second dimension being equal to 3 is '
P(X_2 = 3) = x(3) + x(7) + x(11) + x(15)
I'm writing Matlab code that needs to compute these marginal distributions, but I'm not familiar enough with Matlab to do it in a simple way (it is doable using some ugly recursion, but there has to be a better option).
To calculate P(X_k=z) for a D-dimensional matrix you can use
xD = reshape(x, n*ones(1,D));
B = permute(xD, [k setdiff(1:D, k)]);
P = sum(B(z,:));
It first makes it a D-dimensional matrix. It brings the dimension of interest k to the beginning and then chooses the z-th element and sums over elements corresponding to that.
Mohsen Nosratinia's answer would be my first option. As an alternative, it can be done without reshaping or permuting dimensions, which can result in faster code:
k = 2; %// chosen dimension
z = 3; %// chosen value (along d-th dimension)
result = sum(x(mod(floor((0:end-1)/n^(k-1)), n)==z-1));

Solve matrix equation in matlab

I have an equation of the type c = Ax + By where c, x and y are vectors of dimensions say 50,000 X 1, and A and B are matrices with dimensions 50,000 X 50,000.
Is there any way in Matlab to find matrices A and B when c, x and y are known?
I have about 100,000 samples of c, x, and y. A and B remain the same for all.
Let X be the collection of all 100,000 xs you got (such that the i-th column of X equals the x_i-th vector).
In the same manner we can define Y and C as 2D collections of ys and cs respectively.
What you wish to solve is for A and B such that
C = AX + BY
You have 2 * 50,000^2 unknowns (all entries of A and B) and numel(C) equations.
So, if the number of data vectors you have is 100,000 you have a single solution (up to linearly dependent samples). If you have more than 100,000 samples you may seek for a least-squares solution.
Re-writing:
C = [A B] * [X ; Y] ==> [X' Y'] * [A';B'] = C'
So, I suppose
[A' ; B'] = pinv( [X' Y'] ) * C'
In matlab:
ABt = pinv( [X' Y'] ) * C';
A = ABt(1:50000,:)';
B = ABt(50001:end,:)';
Correct me if I'm wrong...
EDIT:
It seems like there is quite a fuss around dimensionality here. So, I'll try and make it as clear as possible.
Model: There are two (unknown) matrices A and B, each of size 50,000x50,000 (total 5e9 unknowns).
An observation is a triplet of vectors: (x,y,c) each such vector has 50,000 elements (total of 150,000 observed points at each sample). The underlying model assumption is that an observation is generated by c = Ax + By in this model.
The task: given n observations (that is n triplets of vectors { (x_i, y_i, c_i) }_i=1..n) the task is to uncover A and B.
Now, each sample (x_i,y_i,c_i) induces 50,000 equations of the form c_i = Ax_i + By_i in the unknown A and B. If the number of samples n is greater than 100,000, then there are more than 50,000 * 100,000 ( > 5e9 ) equations and the system is over constraint.
To write the system in a matrix form I proposed to stack all observations into matrices:
A matrix X of size 50,000 x n with its i-th column equals to observed x_i
A matrix Y of size 50,000 x n with its i-th column equals to observed y_i
A matrix C of size 50,000 x n with its i-th column equals to observed c_i
With these matrices we can write the model as:
C = A*X + B*Y
I hope this clears things up a bit.
Thank you #Dan and #woodchips for your interest and enlightening comments.
EDIT (2):
Submitting the following code to octave. In this example instead of 50,000 dimension I work with only 2, instead of n=100,000 observations I settled for n=100:
n = 100;
A = rand(2,2);
B = rand(2,2);
X = rand(2,n);
Y = rand(2,n);
C = A*X + B*Y + .001*randn(size(X)); % adding noise to observations
ABt = pinv( [ X' Y'] ) * C';
Checking the difference between ground truth model (A and B) and recovered ABt:
ABt - [A' ; B']
Yields
ans =
5.8457e-05 3.0483e-04
1.1023e-04 6.1842e-05
-1.2277e-04 -3.2866e-04
-3.1930e-05 -5.2149e-05
Which is close enough to zero. (remember, the observations were noisy and solution is a least-square one).