3

I have two numpy arrays image and warped_image and indices arrays ix,iy. I need to add image to warped_image such that image[i,j] is added to warped_image[iy[i,j],ix[i,j]]. The below code works if the pairs (iy[i,j], ix[i,j]) are unique for all i,j. But when they are not unique i.e. when 2 elements from image need to be added to the same element in warped_image, only one of them gets added. How can I add both elements from image to the same element in warped_image?

Note that, I don't want to use any for loops. I want to keep this vectorized. I'm planning to convert the code to TensorFlow or PyTorch in the future to use GPU capabilities for this. That's because, I have hundreds of such images and each image is of full HD resolution.

import numpy
image = numpy.array([[246,  50, 101], [116,   1, 113], [187, 110,  64]])
iy = numpy.array([[1, 0, 2], [1, 1, 0], [2, 0, 2]])
ix = numpy.array([[0, 2, 1], [1, 2, 0], [0, 1, 2]])
warped_image = numpy.zeros(shape=image.shape)
warped_image[iy, ix] += image

>> warped_image
Out[31]: 
array([[  113., 110.,  50.],
       [246., 116.,   1.],
       [187., 101.,  64.]])
   

For the above case, indices are unique and hence the output is as expected.

import numpy
image = numpy.array([[246,  50, 101], [116,   1, 113], [187, 110,  64]])
iy = numpy.array([[1, 0, 2], [1, 0, 2], [2, 2, 2]])
ix = numpy.array([[0, 2, 1], [1, 2, 0], [0, 1, 2]])
warped_image = numpy.zeros(shape=image.shape)
warped_image[iy, ix] += image

>> warped_image
Out[32]: 
array([[  0.,   0.,   1.],
       [246., 116.,   0.],
       [187., 110.,  64.]])
   

Expected Output:

array([[  0.,   0.,   51.],
       [246., 116.,   0.],
       [300., 211.,  64.]])
       

In this case, there are 3 pairs of indices which overlap and hence it fails. E.g. image[0,1] and image[1,1] should gt added to warped_image[0,2] to give a value 51. However only one of them (image[1,1]) gets added to give a value 1.

Context:
I'm trying to do warp an image from view1 to view2. I've computed which pixel has to go where. In case of overlapping pixels, I need to take a weighted average of them. So, I need to achieve the above. More details here

Nagabhushan S N
  • 6,407
  • 8
  • 44
  • 87

1 Answers1

1

Use numpy.add.at:

import numpy
image = numpy.array([[246,  50, 101], [116,   1, 113], [187, 110,  64]])
iy = numpy.array([[1, 0, 2], [1, 0, 2], [2, 2, 2]])
ix = numpy.array([[0, 2, 1], [1, 2, 0], [0, 1, 2]])
warped_image = numpy.zeros(shape=image.shape)

np.add.at(warped_image, (iy, ix), image)

print(warped_image)

Output

[[  0.   0.  51.]
 [246. 116.   0.]
 [300. 211.  64.]]
Dani Mesejo
  • 61,499
  • 6
  • 49
  • 76
  • Awesome! Thanks a lot. I've been stuck here for far too long. Any idea if this functionality is implemented in TensorFlow or PyTorch? – Nagabhushan S N Nov 27 '20 at 14:16
  • 1
    Perhaps [this](https://stackoverflow.com/questions/40389822/equivalent-for-np-add-at-in-tensorflow) can help – Dani Mesejo Nov 27 '20 at 14:17