使用PIL使所有白色像素透明?

has*_*man 54 python image python-imaging-library

我正在尝试使用Python Image Library使所有白色像素透明.(我是一个C黑客试图学习python所以要温柔)我已经有转换工作(至少像素值看起来正确)但我无法弄清楚如何将列表转换为缓冲区来重新创建图片.这是代码

img = Image.open('img.png')
imga = img.convert("RGBA")
datas = imga.getdata()

newData = list()
for item in datas:
    if item[0] == 255 and item[1] == 255 and item[2] == 255:
        newData.append([255, 255, 255, 0])
    else:
        newData.append(item)

imgb = Image.frombuffer("RGBA", imga.size, newData, "raw", "RGBA", 0, 1)
imgb.save("img2.png", "PNG")
Run Code Online (Sandbox Code Playgroud)

cr3*_*333 77

您需要进行以下更改:

  • 附加元组(255, 255, 255, 0)而不是列表[255, 255, 255, 0]
  • 使用 img.putdata(newData)

这是工作代码:

from PIL import Image

img = Image.open('img.png')
img = img.convert("RGBA")
datas = img.getdata()

newData = []
for item in datas:
    if item[0] == 255 and item[1] == 255 and item[2] == 255:
        newData.append((255, 255, 255, 0))
    else:
        newData.append(item)

img.putdata(newData)
img.save("img2.png", "PNG")
Run Code Online (Sandbox Code Playgroud)

  • 只是为了让你有时间安全:如果你正在使用Python3,你必须使用Pillow(http://python-pillow.org/)而不是PIL. (7认同)
  • “RGBA”中的 A 代表“alpha”,意思是“不透明度”。所以这里`newData.append((255,255,255,0))`中的`0`表示“0不透明度;” 换句话说,“完全透明”。进一步的解释可能会帮助好奇的新手。我猜测 `putdata()` 会改变 PIL 对象,但我不知道幕后发生了什么 (2认同)

kei*_*thb 40

您还可以使用像素访问模式来就地修改图像:

from PIL import Image

img = Image.open('img.png')
img = img.convert("RGBA")

pixdata = img.load()

width, height = image.size
for y in xrange(height):
    for x in xrange(width):
        if pixdata[x, y] == (255, 255, 255, 255):
            pixdata[x, y] = (255, 255, 255, 0)

img.save("img2.png", "PNG")
Run Code Online (Sandbox Code Playgroud)

  • 作为效率的参考点,上述循环在我的普通机器上的 256x256 图像上大约需要 0.05 秒。这比我预期的要快。 (2认同)

Dar*_*rdo 7

import Image
import ImageMath

def distance2(a, b):
    return (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2])

def makeColorTransparent(image, color, thresh2=0):
    image = image.convert("RGBA")
    red, green, blue, alpha = image.split()
    image.putalpha(ImageMath.eval("""convert(((((t - d(c, (r, g, b))) >> 31) + 1) ^ 1) * a, 'L')""",
        t=thresh2, d=distance2, c=color, r=red, g=green, b=blue, a=alpha))
    return image

if __name__ == '__main__':
    import sys
    makeColorTransparent(Image.open(sys.argv[1]), (255, 255, 255)).save(sys.argv[2]);
Run Code Online (Sandbox Code Playgroud)


Mar*_*aci 5

由于这是目前在寻找“枕头白色到透明”时的第一个 Google 结果,我想补充一点,使用 numpy 也可以实现相同的结果,并且在我的基准测试中(具有大量白色背景的单个 8MP 图像)大约是快 10 倍(大约 300 毫秒与建议解决方案的 3.28 秒)。代码也有点短:

import numpy as np

def white_to_transparency(img):
    x = np.asarray(img.convert('RGBA')).copy()

    x[:, :, 3] = (255 * (x[:, :, :3] != 255).any(axis=2)).astype(np.uint8)

    return Image.fromarray(x)
Run Code Online (Sandbox Code Playgroud)

它也很容易转换为“几乎白色”(例如,一个通道是 254 而不是 255)“几乎透明”的版本。当然这会使整个图片部分透明,除了纯黑色:

def white_to_transparency_gradient(img):
    x = np.asarray(img.convert('RGBA')).copy()

    x[:, :, 3] = (255 - x[:, :, :3].mean(axis=2)).astype(np.uint8)

    return Image.fromarray(x)
Run Code Online (Sandbox Code Playgroud)

备注:这.copy()是必需的,因为默认情况下 Pillow 图像被转换为​​只读数组。


小智 5

一种更Pythonic的方式,因为对于大图像来说循环需要很长时间

from PIL import Image

img = Image.open('img.png')
img = img.convert("RGBA")

imgnp = np.array(img)

white = np.sum(imgnp[:,:,:3], axis=2)
white_mask = np.where(white == 255*3, 1, 0)

alpha = np.where(white_mask, 0, imgnp[:,:,-1])

imgnp[:,:,-1] = alpha 

img = Image.fromarray(np.uint8(imgnp))
img.save("img2.png", "PNG")
Run Code Online (Sandbox Code Playgroud)


Jon*_*uwe 5

该函数结合了之前解决方案的所有优点:它允许任何背景并使用 numpy(比经典列表更快)。

import numpy as np
from PIL import Image

def convert_png_transparent(src_file, dst_file, bg_color=(255,255,255)):
    image = Image.open(src_file).convert("RGBA")
    array = np.array(image, dtype=np.ubyte)
    mask = (array[:,:,:3] == bg_color).all(axis=2)
    alpha = np.where(mask, 0, 255)
    array[:,:,-1] = alpha
    Image.fromarray(np.ubyte(array)).save(dst_file, "PNG")
Run Code Online (Sandbox Code Playgroud)