Numpy Equivalent of Nesting For loops for approximate pixel color change

Viewed 38

The follow code shows how to change a a pixel in a 3D image with numpy using for loops. As you can see, the truth value is a few logical ANDs where an RGB pixel value must be within a certain range. I am wondering how to do this since with numpy parallelism. I have tried many combinations of np.where, but none of them work because of this error that usually says: "truth value ambiguous use a.any() a.all()". I would simply like to recreate the nested for loop result in this code with numpy methods. This should work on any image imported with 3 dimensions where the RGB value is [0,1]. Thanks.

import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import numpy as np

avatar = mpimg.imread("some_image.png")

#Looking for pixels that approximate the color red for the color green (thresholding)
#i.e:
#red = np.array([1,0,0,1])
#green = np.array([0,1,0,1])

avatar2 = np.copy(avatar)

for x in range(len(avatar2)):
    for y in range(len(avatar2[0])):
        if (avatar2[x,y][0] > .95 and 
            avatar2[x,y][3] > .95 and
            avatar2[x,y][1] < .05 and
            avatar2[x,y][2] < .05
           ):
            avatar2[x,y] = [0,1,0,1]

plt.imshow(avatar1)
plt.imshow(avatar2)
1 Answers

You could do something like this:

import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import numpy as np

avatar = mpimg.imread('image.png')
avatar2 = avatar.copy()

print('Input')
plt.imshow(avatar)
plt.show()

mask = ((avatar[:, :, 0] > .95) & 
        (avatar[:, :, 1] < .05) & 
        (avatar[:, :, 2] < .05) & 
        (avatar[:, :, 3] > .95)
       )
avatar2[mask, :] = [0, 1, 0, 1]

print('Output')
plt.imshow(avatar2)
plt.show()

Result:

enter image description here

There is a way to do it in one go, but it will be slower due to the more complicated operations:

mask = (np.sign(avatar - [0.95, 0.05, 0.05, 0.95]) == [1, -1, -1, 1]).all(axis=-1)

However, note that libraries like OpenCV have specialised functions for this, like inRange.

Related