Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the equivalent way of doing this type of pythonic vectorized assignment in MATLAB?

I'm trying to translate this line of code from Python to MATLAB:

new_img[M[0, :] - corners[0][0], M[1, :] - corners[1][0], :] = img[T[0, :], T[1, :], :]

So, naturally, I wrote something like this:

new_img(M(1,:)-corners(2,1),M(2,:)-corners(2,2),:) = img(T(1,:),T(2,:),:);

But it gives me the following error when it reaches that line:

Requested 106275x106275x3 (252.4GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See array size limit or preference panel for more information.

This has made me believe that it is not assigning things correctly. Img is at most a 1000 × 1500 RGB image. The same code works in less than 5 seconds in Python. How can I do vector assignment like the code in the first line in MATLAB?

By the way, I didn't paste all lines of my code for this post not to get too long. If I need to add anything else, please let me know.

Edit: Here's an explanation of what I want my code to do (basically, this is what the Python code does):

Consider this line of code. It's not a real MATLAB code, I'm just trying to explain what I want to do:

A([2 3 5], [1 3 5]) = B([1 2 3], [2 4 6])

It is interpreted like this:

A(2,1) = B(1,2)
A(3,1) = B(2,2)
A(5,1) = B(3,2)
A(2,3) = B(1,4)
A(3,3) = B(2,4)
A(5,3) = B(3,4)
...
...
...

Instead, I want it to be interpreted like this:

A(2,1) = B(1,2)
A(3,3) = B(2,4)
A(5,5) = B(3,6)
like image 447
stressed out Avatar asked Dec 12 '18 19:12

stressed out


1 Answers

When you do A[vector1, vector2] in Python, you index the set:

A[vector1[0], vector2[0]]
A[vector1[1], vector2[1]]
A[vector1[2], vector2[2]]
A[vector1[3], vector2[3]]
...

In MATLAB, the similar-looking A(vector1, vector2) instead indexes the set:

A(vector1(1), vector2(1))
A(vector1(1), vector2(2))
A(vector1(1), vector2(3))
A(vector1(1), vector2(4))
...
A(vector1(2), vector2(1))
A(vector1(2), vector2(2))
A(vector1(2), vector2(3))
A(vector1(2), vector2(4))
...

That is, you get each combination of indices. You should think of it as a sub-array composed of the rows and columns specified in the two vectors.

To accomplish the same as the Python code, you need to use linear indexing:

index = sub2ind(size(A), vector1, vector2);
A(index)

Thus, your MATLAB code should do:

index1 = sub2ind(size(new_img), M(1,:)-corners(2,1), M(2,:)-corners(2,2));
index2 = sub2ind(size(img), T(1,:), T(2,:));

% these indices are for first 2 dims only, need to index in 3rd dim also:
offset1 = size(new_img,1) * size(new_img,2);
offset2 = size(img,1) * size(img,2);
index1 = index1.' + offset1 * (0:size(new_img,3)-1);
index2 = index2.' + offset2 * (0:size(new_img,3)-1);

new_img(index1) = img(index2);

What the middle block does here is add linear indexes for the same elements along the 3rd dimension. If ii is the linear index to an element in the first channel, then ii + offset1 is an index to the same element in the second channel, and ii + 2*offset1 is an index to the same element in the third channel, etc. So here we're generating indices to all those matrix elements. The + operation is doing implicit singleton expansion (what they call "broadcasting" in Python). If you have an older version of MATLAB this will fail, you need to replace that A+B with bsxfun(@plus,A,B).

like image 96
Cris Luengo Avatar answered Sep 27 '22 17:09

Cris Luengo