开发者

Numpy.putmask with images

开发者 https://www.devze.com 2023-02-21 16:40 出处:网络
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:

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')
0

精彩评论

暂无评论...
验证码 换一张
取 消