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


72

我正在尝试使用Python图像库使所有白色像素透明。(我是一位尝试学习python的C黑客,所以要谦虚)我已经完成了转换工作(至少像素值看起来正确),但是我不知道如何将列表转换为缓冲区以重新创建图片。这是代码

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")

Answers:


99

您需要进行以下更改:

  • 追加一个元组(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")

7
为了使您安全一些:如果您正在使用Python3,则必须使用Pillow(python-pillow.org)而不是PIL。

1
对于GIF,似乎transparency需要将其作为保存参数(5.1.0版)。另请参阅如何使用PIL(python-imaging)创建透明的gif(或png)
处理

2
“ RGBA”中的A代表“ alpha”,表示“不透明”。因此,这里的0innewData.append((255,255,255,0))表示“ 0不透明度;” 换句话说,“完全透明”。进一步的解释可能会对好奇的新手有所帮助。我猜想putdata()是PIL对象发生了变化,但我不知道幕后发生了什么
Nathan

这足以使一些图像翻转有趣-知道为什么吗?
Rami.K

什么样的翻转?你可以说得更详细点吗?
cr333 '20

46

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

from PIL import Image

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

pixdata = img.load()

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

img.save("img2.png", "PNG")

如果经常使用,您也可以将以上内容包装到脚本中。


2
作为效率的参考,在我的普通计算机上,对256x256图像,上述循环大约需要0.05秒。那比我预期的要快。
M Katz

1
上行空间:这实际上适用于巨型图像(32000x32000 px)。在高端服务器上进行测试时,我尝试使用的所有其他方法均因该大小的内存错误而死亡,但能够处理(22000x22000 px)。缺点:这比我尝试过的其他方法(例如,使用numpy替换值,然后Image.fromarray将其返回到PIL对象)的速度慢。为了增加@MKatz的参考点,对于32000x32000 px的图像,此过程需要7分钟15秒。
kevinmicke '18年

嘿,有一种方法可以使除一种颜色以外的所有颜色透明?我尝试使用for循环,但是这花费了太多时间!帮助
Nithin Sai

@NithinSai如何创建仅复制原始图片中的一种颜色的副本?
DonCarleone

1
@NithinSai lmk如果有帮助的话:stackoverflow.com/questions/52315895/…–
DonCarleone

8
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]);

3

由于这是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)

对于“几乎白色”(例如,一个通道是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)

备注:.copy()之所以需要,是因为默认情况下,枕头图像会转换为只读数组。


此功能将占用大量内存。
gotounix

为什么很多?它在空间上仍然是线性的,请确保您需要创建一些其他的数组,但是即使考虑到所有因素,它可能是5倍的空间(可能更少),对于10倍的加速,这是一个很好的权衡(同样,如果您在这样的环境中工作)严格的条件下,您无法在内存中创建5张图像,那么python可能不是您执行任务的正确语言...)
Marco Spinaci

我在1G VPS中始终使用此错误获取内存错误异常,同时增加VPS内存一切正常。
gotounix

你能解释为什么使用axis = 2吗?我假设它应该是轴= 3,因为我们使Alpha'A'通道透明。
fdabhi

图像总共有3个轴-高度,宽度和通道-因此轴= 3将引发错误。我们保存为alpha的事实已包含在分配的lhs中,即,我们正在写入第三把斧的索引3(R = 0,G = 1,B = 2,alpha = 3)。在.any(axis=2)等式右边的手段,你想要得到的像素其中前三个指标中的至少一个第三维的(R,G,或B)(因为它的[:, :, :3])是从255不同
马可Spinaci

2

自从循环播放大图像以来,花费了很长时间,这是一种更加Python化的方式

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")

1

Python 3版本,所有文件都在目录中

import glob
from PIL import Image

def transparent(myimage):
    img = Image.open(myimage)
    img = img.convert("RGBA")

    pixdata = img.load()

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

    img.save(myimage, "PNG")

for image in glob.glob("*.png"):
    transparent(image)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.