Matlab Matrix one-to-one correspondence index - matlab

I have a small code below for one-to-one correspondence index of the img matrix
for k = 1:length(I)
img(I(k),J(k)) = 0;
end
Now, I hope to get rid of for loop, but I cannot find proper matlab syntax to realize it.
img(I(1:length(I)), J(1:length(I)),1:3) = 0;
is not one-to-one correspondence index. Any help to realize the same function is appreciated.

Indexing in a linear fashion along multiple dimensions can be done using the sub2ind function:
img(sub2ind(size(img), I, J(1:length(I))) = 0;

You can also use sparse to get this done:
ind = sparse(I, J, 1, size(img,1), size(img,2)) == 1;
img(ind) = 0;
The first line of code generates a sparse matrix where the row values stored in I and the column values stored in J set the matrix values to 1, and we ensure that this is the same size as your image. We also convert to a logical array by equating the statement with 1. When you're done, simply use the result to index into your actual array and set the values to 0.
If you have a multi-channel matrix, you can do this temporally by making a call to repmat:
img(repmat(ind, [1 1 size(img,3)])) = 0;

Related

Accelerating the index in huge sparse matrix during loop in MATLAB

I need to construct a huge sparse matrix in iterations. The code is as follow:
function Huge_Matrix = Create_Huge_Matrix(len, Weight, Index)
k = size(Weight,1);
Huge_Matrix = spalloc(len, len,floor(len*k));
parfor i = 1:len
temp = sparse(1,len);
ind = Index(:,i);
temp(ind) = Weight(:,i);
Huge_Matrix(i,:) = temp;
end
Huge_Matrix = Huge_Matrix + spdiags(-k*ones(len,1),0,len,len);
end
As is shown, len is size of the height * weight of the input image, for 200*200 image, the len is 40000! And I am assigning the Weight into this huge matrix according the position stored in Index. Even though I use parfor to accerlate the loop, the speed is very slow.
I also try to create full matrix at first, it seems that the code can becomes faster, but memory is limited. Is there any other way to speed up the code? Thanks in advance!
As #CrisLuengo says in the comments, there is probably a better way to do what you're trying to do than to create a 40kx40k matrix, but if you have to create a large sparse matrix, it's better to let MATLAB do it for you.
The sparse function has a signature that takes lists of rows, columns and the corresponding values for the nonzero elements of the matrix:
S = sparse(i,j,v) generates a sparse matrix S from the triplets i, j, and v such that S(i(k),j(k)) = v(k). The max(i)-by-max(j) output matrix has space allotted for length(v) nonzero elements. sparse adds together elements in v that have duplicate subscripts in i and j.
If the inputs i, j, and v are vectors or matrices, they must have the same number of elements. Alternatively, the argument v and/or one of the arguments i or j can be scalars.
So, we can simply pass Index as the row indices and Weight as the values, so all we need is an array of column indices the same size as Index:
col_idx = repmat(1:len, k, 1);
Huge_Matrix = sparse(Index, col_idx, Weight, len, len);
(The last two parameters specify the size of the sparse matrix.)
The next step is to create another large sparse matrix and add it to the first. That seems kind of wasteful, so why not just add those entries to the existing arrays before creating the matrix?
Here's the final function:
function Huge_Matrix = Create_Huge_Matrix(len, Weight, Index)
k = size(Weight,1);
% add diagonal indices/weights to arrays
% this avoids creating second huge sparse array
Index(end+1, :) = [1:len];
Weight(end+1, :) = -k*ones(1,len);
% create array of column numbers corresponding to each Index
% make k+1 rows because we've added the diagonal
col_idx = repmat(1:len, k+1, 1);
% let sparse do the work
Huge_Matrix = sparse(Index, col_idx, Weight, len, len);
end

Indexing a set of indices to a matrix

I retrieved all non-white pixel from an image :
[ii, jj] = find(BlackOnWhite < 255)
Then I tried to index those pixel coordinates to a matrix :
image(ii, jj) = 0
But zeros do not appear in the expected places. How can I put zeros only in the places specified by pairs from ii and jj (i.e. [ii(1), jj(1)], [ii(2), jj(2)] etc.)?
A simple way to do that is to use linear indexing. This means using a single index that traverses all entries in the matrix (down, then across). In your case:
Use find with one ouput. This gives the linear indices of the desired pixels.
Use that to index into the matrix.
So:
ind = find(BlackOnWhite < 255);
image(ind) = 0;
You can even remove find and use logical indexing. This means that the result of the logical comparison is directly used as an index:
ind = BlackOnWhite < 255;
image(ind) = 0;
The problem with the code shown in your question is that ii and jj are being used as "subscript indices". This selects all pairs formed by any value from ii and any value from jj, which is not what you want.
If you have subscripts ii and jj like in your question and you need to only select corresponding values from each subscript (instead of all pairs), you can use sub2ind to convert to a linear index:
[ii, jj] = find(BlackOnWhite < 255);
image(sub2ind(size(image), ii, jj)) = 0;
It doesn't work because MATLAB treats the subscripts as a grid, which means roughly "set all intersection of any of ii and any of jj to zero" and not "set the locations specified by these separate pairs of coordinates to zero".
In some cases (but not this one) you might need to convert a set of subscripts to indices, in which case I suggest familiarizing yourself with sub2ind.
As mentioned in the other answer(s), the best thing to do in your case is simply:
image(BlackOnWhite < 255) = 0;

Access a list of entries in MATLAB

I have a huge matrix MxN matrix, say, A=rand([M,N]); and an index vector with N integer values between 1 and M, say, RandomIndex = randi(M,[1,N]);.
Now I would like to generate a row vector with entries
result = [A(RandomIndex(1),1), A(RandomIndex(2),2), ..., A(RandomIndex(N),N)]
What would be an efficient way to do this? It should be a very cheap operation but all my implementations are slow. I don't think there is a notation in Matlab to do this directly, is there?
The fastest option so far is
indexFunction = #(r,c) A(r,c);
result = cell2mat(arrayfun(indexFunction,RandomIndex,1:N,'UniformOutput',false));
Is there a more efficient way?
Use sub2ind
A(sub2ind(size(A), RandomIndex, 1:N))
sub2ind will convert the row and column indices given by RandomIndex and 1:N to linear indices based on size(A) which you can then use to index A directly.
Another way to do this is to use RandomIndex and 1:N to return an NxN matrix and then take the diagonal of this with diag
diag(A(RandomIndex, 1:N)).'
Note: .' is used to convert the row vector returned by diag to a column vector.
M=10;N=50;
A=rand([M,N]);
RandomIndex = randi(M,[1,N]);
out = zeros(1,numel(RandomIndex));
for ii = 1:numel(RandomIndex)
out(ii)=A(RandomIndex(ii),ii);
end
Another approach would be to use sparse and logical indexing:
M = sparse(RandomIndex, 1:N, 1) == 1;
out = A(M);
The first line of code generates a logical matrix where there is only 1 true value set in each column. This is defined by each value of RandomIndex. We convert this to a logical matrix, then index into your matrix to obtain the final random vector.
Use your index directly.
M = 100;N=100;
A = rand(M,N);
% get a random index that can be as large as your matrix
% 10 rows by 1 column
idx = randi(numel(A), 10,1);
t = A(idx);

How to set a value of a sparse matrix to 0 without discarding the index

so I have the following scenario for a sparse matrix $X$:
for k = 1 : long_loop
X(indexA{k}) = stuff;
end
X(indexB) = 0;
where some indices in indexA{k} and indexB overlap. The situation is, if I set indexB to 0, then MATLAB throws out the indexes in indexB from the definition of X, and then when those indices come up again in the loop, they are reallocated, and it makes the loop run very very slowly. What I would like to do is to set the values X indexed by indexB to 0 without discarding the indices. I currently set it up by using
X(indexB) = eps;
but I don't think that's a great solution, since eps is going to be a source of error later.
Any way to set the values of a sparse matrix to 0 without discarding the index?
Thanks!

Selecting entries from a matrix without using a loop

I have two matrices A and B, both of which are Nx3 matrices.
I'm currently getting the maximum value and index for each row of matrix A using:
[maxA, idx] = max(A, [], 2)
idx(j) indicates which column contained the maximum for row j. Now I'd like to select those same positions from matrix B.
I've currently implemented this using a loop:
for j = 1:numel(idx)
maxB(j) = B(j, idx(j))
end
My current implementation is fast enough, although I prefer to avoid unneeded loops so is there a way to express this without a loop?
You can build a vector of linear indices (I expect B to be the same size as A):
vec_indices = sub2ind(size(A), 1:numel(idx), idx);
Then you can use that vector directly for lookup:
maxB = B(vec_indices)
You can construct the single dimension index into the matrix and get them that way. All multidimensional matrices in matlab can be addressed.
You can use
maxB = B(sub2ind([1:length(idx)]',idx(:)));
In one line:
maxB = B(A == max(A, [], 2) * ones(1, 3));
But this is not safe. It assumes unique values in every row of A.