How can I assign a value to the diagonals of a 4-D matrix using linear indexing in MATLAB? - matlab

I have a 4-D matrix A of size NxNxPxQ. How can I easily change the diagonal values to 1 for each NxN 2-D submatrix in a vectorized way?

Incorporating gnovice's suggestion, an easy way to index the elements is:
[N,~,P,Q]=size(A);%# get dimensions of your matrix
diagIndex=repmat(logical(eye(N)),[1 1 P Q]);%# get logical indices of the diagonals
A(diagIndex)=1;%# now index your matrix and set the diagonals to 1.

You can actually do this very simply by directly computing the linear indices for every diagonal element, then setting them to 1:
[N,N,P,Q] = size(A);
diagIndex = cumsum([1:(N+1):N^2; N^2.*ones(P*Q-1,N)]);
A(diagIndex) = 1;
The above example finds the N diagonal indices for the first N-by-N matrix (1:(N+1):N^2). Each subsequent N-by-N matrix (P*Q-1 of them) is offset by N^2 elements from the last, so a matrix of size PQ-1-by-N containing only the value N^2 is appended to the linear indices for the diagonal of the first matrix. When a cumulative sum is performed over each column using the function CUMSUM, the resulting matrix contains the linear indices for all diagonal elements of the 4-D matrix.

You can use direct indexing, and some faffing about with repmat, to add the indexes for a single 50x50 diagonal to the offsets within the larger matrix of each 50x50 block:
Here's an example for a smaller problem:
A = NaN(10,10,5,3);
inner = repmat(sub2ind([10 10], [1:10],[1:10]), 5*3, 10); % diagonals
outer = repmat([10*10 * [0:5*3-1]]', 1, 10*10); % offsets to blocks
diags = inner + outer;
A(diags(:)) = 1;

Related

Extracting block diagonal from matrix

I have an njxnj matrix made up of nxn matrices. I want to extract the diagonal j blocks of nxn matrices. i.e. I want to extract the diagonal (for n = 2, j = 4):
What would be the most efficient way of doing this?
To index the elements you can use blkdiag to create a corresponding mask.
%your parameters
n=2
j=4
%some example matrix
M=magic(n*j);
%create the input for blkdiag, j matrices of size n
h=repmat({true(n)},j,1)
%use blkdiag to select the elements
M(logical(blkdiag(h{:})))
For large j, this answer of #Daniel becomes slow. I would instead recommend using linear indices of block diagonal.
n=2;
j=4;
%some example matrix
M=magic(n*j);
linIndices = (0:n*((n*j)+1):n*((n*j)+1)*(j-1))+reshape((1:n)'+n*j*(0:n-1),[],1);
newM = reshape(M(linIndices),n,n,[]);

How do i find a matrix of 150*25 from two vectors such that each vector elements multiply with each element of another vector of dim 1*150 &1*25?

I have a vector created from linspace between specific numbers and have dimensions of 1*150. Now i want to multiply each element of the above created vector with another vector whose dimension is 1*25. The detail of my code is given below
c_p = linspace(1,.3*pi,150);
c = c_p';
C = zeros([150,25]);
for i= 1:1:size(C,1)
wp= c(i);
for n= 1:25
c_wp(n) = cos(n*wp);
end
C(i,25)= c_wp;
end
The vector is actually a multiple of cosine of length 25 and here wp is the elements of first vector of dimension 1*150. SO by the logic, I must have an output of 150*25 but instead giving me "subscripted assignment dimension mismatch". Any help would be appreciated, as i am new to matlab.
To multiply each element of a row vector a with each element of another row vector b, we can use linear algebra. We transpose a to make it a column vector and then use matrix multiplication:
a.' * b
That way you don't even need a for loop.

How to access particular matrix element for all blocks in entire image?

I have a 512x512 image , which i made 4x4 block for entire image, then i want access the (3rd row , 3rd element) of the all indivial 4x4 matrices and add it to the index values, which i obtained. Please help me on below code.
[row col] = size(a);
m = zeros(row,col);
count = [(row-4)*(col-4)]/4;
outMat = zeros(4,4,count);
l = 0;
for i=2:4:row-4
for j=2:4:col-4
l = l + 1;
outMat(:,:,l) = double(a(i-1:i+2,j-1:j+2));% for each matrix i have to find(3rd row,3rd element of each matrix.
end;
end;
Adding the (3rd row,3rd element):
m(i,j) = sum(sum(a .* w)); %index value of each 4x4 matrix % w = 4x4 matrix.
LUT = m(i,j)+ outMat(3,3);%(3rd row,3rd element each matrix should be added to all m(i,j) values. In which i fail to add all(3rd row,3rd element) of all 4x4 matrices.
I am going to reword your question so that it's easier to understand, as well as allowing it to be easy for me to write an answer.
From your comments in Kostya's post, you have two images img1 and img2 where they are decomposed into 4 x 4 blocks. outMat would be a 3D matrix where each slice contains a 4 x 4 block extracted from img1. From this, you have a matrix m that stores a weighted sum of 4 x 4 blocks stored outMat.
Next, you'll have another matrix, let's call this outMat2, which also is a 3D matrix where each slice is a 4 x 4 block extracted from img2. From this 3D matrix, you wish to extract the third row and third column of each block, add this to the corresponding position of m and store the output into a variable called LUT.
All you have to do is extract a single vector that slices through all of the slices located at the third row and third column. You would then have to reshape this into a matrix that is the same size as m then add this on top of m and store it into a variable called LUT. Bear in mind that if we reshape this into a matrix, the reshaping will be done in column major format, and so you would stack the values by columns. Because your blocks were created row-wise, what we need to do reshape this matrix so that it has size(m,2) rows and size(m,1) columns then transpose it.
Therefore:
vec = outMat2(3,3,:);
vec = vec(:); %// Make sure it's a 1D vector
m2 = reshape(vec, size(m,2), size(m,1)).';
LUT = m + m2;
LUT will contain a 2D matrix where each element contains the weighted sum of the 4 x 4 blocks from img1 with the corresponding third row, third column of each block in img2.
Next time, please update your question so that you have all of the information. We shouldn't have to dig through your comments to figure out what you want.
I think you can do just
LUT = sum( sum( a(3:4:row,3:4,col) * w(3,3) ) );

How do I find the indices of the elements of one vector in a matrix in Matlab?

Suppose I have a 9x9 matrix A that that consists of integers. I have another matrix IDX that's 2500x4 and consists of the same integers in A. I want to find the indices of all the values in IDX in the matrix A.
Here's what I have:
for ii=1:length(IDX)
Mat_idx=ismember(A,IDX(ii,:));
[StatIdxX StatIdxY] = find(Mat_idx);
end
Now for each ii the StatIdxX and StatIdxY are the row and col indices of IDX in the matrix A. This is slow, and the culprit is ismember
Any thoughts on speeding this up?
Thanks.
first flatten A with A=A(:), that will make a single linear index instead of row,col.
Then just use logical indexing. For example:
B=zeros(size(IDX));
for n=1:numel(A)
B(IDX==A(n))=n;
end

How to normalize a matrix of 3-D vectors

I have a 512x512x3 matrix that stores 512x512 there-dimensional vectors. What is the best way to normalize all those vectors, so that my result are 512x512 vectors with length that equals 1?
At the moment I use for loops, but I don't think that is the best way in MATLAB.
If the vectors are Euclidean, the length of each is the square root of the sum of the squares of its coordinates. To normalize each vector individually so that it has unit length, you need to divide its coordinates by its norm. For that purpose you can use bsxfun:
norm_A = sqrt(sum(A .^ 2, 3)_; %// Calculate Euclidean length
norm_A(norm_A < eps) == 1; %// Avoid division by zero
B = bsxfun(#rdivide, A, norm_A); %// Normalize
where A is your original 3-D vector matrix.
EDIT: Following Shai's comment, added a fix to avoid possible division by zero for null vectors.