Numpy.putmask 与图像
我有一张图片,已经转换成了一个包含RGBA值的数组。假设这个数组的大小是50 x 50 x 4。
我想把所有像素值为array([255, 255, 255, 255])
的地方,替换成array([0, 0, 0, 0])
。也就是说:
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 putmask(mask, mask != find, replace)
mask = Image.open('test.png')
test(mask)
我哪里做错了?这让我遇到了一个ValueError: putmask: mask and data must be the same size
的错误。不过如果我把数组改成数字(查找255,替换成0),那就可以正常工作。
3 个回答
2
这个解决方案使用了 putmask
,我觉得它和提问者的代码最接近。提问者的原始代码中有两个错误需要注意:1) putmask
是一种就地操作,它不会返回任何值,而是返回 None
。2) putmask
还需要两个数组的大小相同。可惜的是,它没有 axis
这个参数。
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')
4
更简洁的做法是
img = Image.open('test.png')
a = numpy.array(img)
a[(a == 255).all(axis=-1)] = 0
img2 = Image.fromarray(a, mode='RGBA')
更一般来说,如果find
和repl
中的项目不完全相同,你也可以这样做
find = [1, 2, 3, 4]
repl = [5, 6, 7, 8]
a[(a == find).all(axis=-1)] = repl
2
一种实现这种通道遮罩的方法是将数组分成红色(r)、绿色(g)、蓝色(b)和透明度(a)四个通道,然后使用numpy的逻辑位运算来定义索引:
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()