Numpy.putmask with images
I have an image converted to a ndarray with RGBA values. Suppose it's 50 x 50 x 4.
I want to replace all the pixels with values array([255, 255, 255, 255])
for array([0, 0, 0, 0])
. So:
from numpy import *
from PIL import Image
def test(mask):
mask = array(mask)
find = array([255, 255, 255, 255])
replace = array([0, 0, 0, 0])
return pu开发者_如何学JAVAtmask(mask, mask != find, replace)
mask = Image.open('test.png')
test(mask)
What am I doing wrong? That gives me a ValueError: putmask: mask and data must be the same size
. Yet if I change the arrays to numbers (find = 255, replace = 0) it works.
A more concise way to do this is
img = Image.open('test.png')
a = numpy.array(img)
a[(a == 255).all(axis=-1)] = 0
img2 = Image.fromarray(a, mode='RGBA')
More generally, if the items of find
and repl
are not all the same, you can also do
find = [1, 2, 3, 4]
repl = [5, 6, 7, 8]
a[(a == find).all(axis=-1)] = repl
One way to do this kind of channel masking is to split the array into r,g,b,a channels, then define the index using numpy logical bit operations:
import numpy as np
import Image
def blackout(img):
arr = np.array(img)
r,g,b,a=arr.T
idx = ((r==255) & (g==255) & (b==255) & (a==255)).T
arr[idx]=0
return arr
img = Image.open('test.png')
mask=blackout(img)
img2=Image.fromarray(mask,mode='RGBA')
img2.show()
This solution uses putmask
and I think is the closest to the OPs code. There are two errors in the original code that the OP should know about: 1) putmask is an in-place operation. It returns None
. 2) putmask
also requires equal-sized arrays. It (too bad) doesn't have an axis
keyword argument.
import numpy as np
from PIL import Image
img1 = Image.open('test.png')
arry = np.array(img1)
find = np.array([255, 255, 255, 255])
repl = np.array([ 0, 0, 0, 0])
# this is the closest to the OPs code I could come up with that
# compares each pixel array with the 'find' array
mask = np.all(arry==find, axis=2)
# I iterate here just in case repl is not always the same value
for i,rep in enumerate(repl):
# putmask works in-place - returns None
np.putmask(arry[:,:,i], mask, rep)
img2 = Image.fromarray(arry, mode='RGBA')
img2.save('testx.png')
精彩评论