Используя PIL, чтобы сделать все белые пиксели прозрачными? - PullRequest
49 голосов
/ 19 апреля 2009

Я пытаюсь сделать все белые пиксели прозрачными, используя библиотеку изображений Python. (Я хакер 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")

Ответы [ 5 ]

68 голосов
/ 19 апреля 2009

Вам необходимо внести следующие изменения:

  • добавить кортеж (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")
39 голосов
/ 19 апреля 2009

Вы также можете использовать режим доступа к пикселям для изменения изображения на месте:

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")
7 голосов
/ 25 декабря 2010
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]);
2 голосов
/ 11 января 2019

Поскольку в настоящее время это первый результат Google при поиске «Подушка от белого до прозрачного», я хотел бы добавить, что того же можно добиться с помощью numpy и моего теста (одно 8-мегапиксельное изображение с большим количеством белого фона). ) примерно в 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() необходим, поскольку по умолчанию изображения подушек преобразуются в массивы только для чтения.

0 голосов
/ 29 ноября 2018

версия 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)
...