Reputation: 3749
I have an image and its mask. I'm using PIL and Numpy to apply the following rules:
(255, 0, 0)
, sets to (0, 0, 0)
. (0, 255, 0)
, sets to (64, 64, 64)
(0, 0, 255)
, sets to (128, 128, 128)
(255, 255, 0)
, sets to (255, 255, 255)
Using the idea of array mask, I tried the following:
import numpy as np
import Image
# (R G B)
red = [255, 0, 0]
green = [0, 255, 0]
blue = [0, 0, 255]
yellow = [255, 255, 0]
def execute():
im = Image.open('input.png')
data = np.array(im)
print "Original = ", data.shape
mask = Image.open('mask2.png')
data_mask = np.array(mask)
print "Mask = ", data_mask.shape
red_mask = data_mask == red
green_mask = data_mask == green
blue_mask = data_mask == blue
yellow_mask = data_mask == yellow
data[red_mask] = [0, 0, 0]
data[green_mask] = [64, 64, 64]
data[blue_mask] = [128, 128, 128]
data[yellow_mask] = [255, 255, 255]
im = Image.fromarray(data)
im.save('output.png')
if __name__ == "__main__":
execute()
The code above outputs:
Original = (64, 64, 3)
Mask = (64, 64, 3)
ValueError: NumPy boolean array indexing assignment cannot assign 3 input values to the 5012 output values where the mask is true
Am I missing something? How can I use the idea of array masks to change pixels values?
Upvotes: 3
Views: 3834
Reputation: 366083
Look at data[data_mask == red]
: it's going to be a flat array, not a 3D array of (X,Y,3). So, the last axis is 5012, not 3. So you can't broadcast the assignment.
The docs explain this:
The result is a 1-D array containing all the elements in the indexed array corresponding to all the true elements in the boolean array.
But…
The result will be multidimensional if y has more dimensions than b. For example:
(Here, y
is the equivalent of your data
, and b
of your red_mask
.)
If you think about it, this makes sense. Your red_mask
is a 64x64x3 array; it can't possibly pick out 3-vectors (pixels), it can only pick out individual values.
Let's take a smaller, simpler, concrete example (a 1D array of 4 pixels, instead of a 2D array of 64x64 pixels), instead of your example which (a) you didn't give us the data for and (b) is too big to look at all at once:
>>> data = np.array([[1,2,3], [4,5,6], [7,8,9], [10,11,12]])
>>> mask = np.array([[1,2,3], [4,5,6], [1,2,3], [4,5,6]])
>>> red = np.array([1,2,3])
>>> red_mask = mask == red
>>> red_mask
array([[ True, True, True],
[False, False, False],
[ True, True, True],
[False, False, False]], dtype=bool)
>>> data[red_mask]
array([1, 2, 3, 7, 8, 9])
>>> data[red_mask] = [0,0,0]
ValueError: NumPy boolean array indexing assignment cannot assign 3 input values to the 6 output values where the mask is true
>>> red_mask[:,0]
array([ True, False, True, False], dtype=bool)
>>> data[red_mask[:,0]]
array([[1, 2, 3],
[7, 8, 9]])
>>> data[red_mask[:,0]] = [0,0,0]
>>> data
array([[ 0, 0, 0],
[ 4, 5, 6],
[ 0, 0, 0],
[10, 11, 12]])
See how red_mask
is the indices of each individual scalar component, while red_mask[:,0]
is the indices of each whole 3-vector pixel?
Upvotes: 4