Как объединить прозрачное изображение PNG с другим изображением, используя PIL


151

У меня есть прозрачное изображение png "foo.png", и я открыл другое изображение с

im = Image.open("foo2.png");

Теперь мне нужно объединить foo.png с foo2.png.

(foo.png содержит некоторый текст, и я хочу напечатать этот текст на foo2.png)


71
Не используйте ;в конце своих команд в python: это уродливо ...
nosklo

6
Я буду помнить об этом, спасибо !!
Аракна

Ответы:


288
import Image

background = Image.open("test1.png")
foreground = Image.open("test2.png")

background.paste(foreground, (0, 0), foreground)
background.show()

Первый параметр .paste()- это изображение для вставки. Вторые - это координаты, а секретный соус - третий параметр. Указывает маску, которая будет использоваться для вставки изображения. Если вы передаете изображение с прозрачностью, то альфа-канал используется в качестве маски.

Проверьте документы .


6
Чтобы во всех случаях передний план содержал прозрачность, используйте foreground.convert('RGBA')параметр маски.
Марк Рэнсом

2
Спасибо. Мне слишком не хватало третьего параметра.
Силуан Жерин

13
Я получаюValueError: bad transparency mask
Дениз Озгер

2
Секретный соус был вкусным
AFP_555

3
@DenizOzger Чтобы исправить ValueError: bad transparency maskиспользованиеbg.paste(fg, (0, 0), fg.convert('RGBA'))
Mingwei Samuel

66

Image.pasteне работает должным образом, когда фоновое изображение также содержит прозрачность. Вам нужно использовать настоящий альфа-композитинг .

Подушка 2.0 содержит alpha_compositeфункцию, которая делает это.

background = Image.open("test1.png")
foreground = Image.open("test2.png")

Image.alpha_composite(background, foreground).save("test3.png")

РЕДАКТИРОВАТЬ: оба изображения должны быть типа RGBA. Поэтому вам нужно вызывать их, convert('RGBA')если они имеют палитру и т. Д. Если фон не имеет альфа-канала, вы можете использовать обычный метод вставки (который должен быть быстрее).


Я просто использовал paste () для наложения одного полупрозрачного изображения на другое с помощью PIL, и это сработало, как я и ожидал. Как это не работает, как вы ожидали?
Питер Хансен

3
@PeterHansen, paste () не работает должным образом, «когда фоновое изображение также содержит прозрачность».
Homm

1
@PeterHansen Вот пример: github.com/python-pillow/Pillow/issues/…
Homm

@ спасибо. Это было так давно, я не помню, что я пытался. Вероятно, я пропустил ту часть, которую вы процитировали о фоновом изображении, также имеющем прозрачность
Питер Хансен

4
Я получаю ValueError: image has wrong made, а @DenizOzger
digitaldavenyc

48

Как уже указывало olt , Image.pasteне работает должным образом, когда источник и пункт назначения содержат альфа.

Рассмотрим следующий сценарий:

Два тестовых изображения, оба содержат альфа:

введите описание изображения здесь введите описание изображения здесь

layer1 = Image.open("layer1.png")
layer2 = Image.open("layer2.png")

Компоновка изображения осуществляется Image.pasteтак:

final1 = Image.new("RGBA", layer1.size)
final1.paste(layer1, (0,0), layer1)
final1.paste(layer2, (0,0), layer2)

создает следующее изображение (альфа-часть наложенных красных пикселей полностью взята со 2-го слоя. Пиксели не смешаны правильно):

введите описание изображения здесь

Компоновка изображения осуществляется Image.alpha_compositeтак:

final2 = Image.new("RGBA", layer1.size)
final2 = Image.alpha_composite(final2, layer1)
final2 = Image.alpha_composite(final2, layer2)

производит следующее (правильное) изображение:

введите описание изображения здесь


1
Спасибо за скриншоты! Действительно помогает!
Вьетнам

1
Но alpha_compositeне можете установить смещение, не могли бы вы привести пример полной замены pasteфункции?
Мифрил

3
Я предполагаю, что вам нужно будет создать новое пустое изображение того же размера, что и изображение цели, вставить слой в нужное положение и использовать alpha_compositing, чтобы смешать новое изображение с целевым изображением.
P.Melch

11

Можно также использовать смешивание:

im1 = Image.open("im1.png")
im2 = Image.open("im2.png")
blended = Image.blend(im1, im2, alpha=0.5)
blended.save("blended.png")

1
Этот аскетично работал для меня. Изображения должны иметь точно такой же размер, но это нормально. Функция вставки мне не очень
Ливиу Сосу,

2
«ValueError: изображения не совпадают»
Schütze

2
Возможно, они имеют разные размеры. Возможно, вам придется масштабировать или обрезать один из них.
NVD

2
@ Schütze см. Комментарий nvd, потому что он / она не пинговал (используя @blahblah) вас
MilkyWay90

1
def trans_paste(bg_img,fg_img,box=(0,0)):
    fg_img_trans = Image.new("RGBA",bg_img.size)
    fg_img_trans.paste(fg_img,box,mask=fg_img)
    new_img = Image.alpha_composite(bg_img,fg_img_trans)
    return new_img

2
Привет, вы можете добавить немного больше контекста к вашему ответу? В противном случае запросчик вряд ли узнает «почему».
jimf

0

У меня был похожий вопрос, и он не мог найти ответ. Следующая функция позволяет вставить изображение с параметром прозрачности поверх другого изображения с определенным смещением.

import Image

def trans_paste(fg_img,bg_img,alpha=1.0,box=(0,0)):
    fg_img_trans = Image.new("RGBA",fg_img.size)
    fg_img_trans = Image.blend(fg_img_trans,fg_img,alpha)
    bg_img.paste(fg_img_trans,box,fg_img_trans)
    return bg_img

bg_img = Image.open("bg.png")
fg_img = Image.open("fg.png")
p = trans_paste(fg_img,bg_img,.7,(250,100))
p.show()

ValueError: images do not match
lllllllllllll

0

Я закончил тем, что кодировал себя предложение этого комментария сделанным пользователем @ P.Melch и предложенным @Mithril для проекта, над которым я работаю.

Я также написал код безопасности, вот код для него . (Я связал конкретный коммит, потому что в будущем этот репозиторий может измениться)

Примечание. Я ожидаю, что на изображениях будут использоваться массивы, такие np.array(Image.open(...))как входы A и B copy_fromи эта связанная функцияoverlay аргументы .

Зависимости - это функция непосредственно перед ней, copy_fromметод и массивы numpy в качестве содержимого изображения PIL для нарезки.

Хотя файл ориентирован на классы, если вы хотите использовать эту функцию overlay_transparent, не забудьте переименовать self.frameмассив в фоновый рисунок.

Или вы можете просто скопировать весь файл (возможно, удалить некоторые импорта и Utilsкласс) и взаимодействовать с этим классом Frame следующим образом:

# Assuming you named the file frame.py in the same directory
from frame import Frame

background = Frame()
overlay = Frame()

background.load_from_path("your path here")
overlay.load_from_path("your path here")

background.overlay_transparent(overlay.frame, x=300, y=200)

Затем у вас есть background.frameналоженный и альфа-составной массив, вы можете получить из него изображение PIL с помощью overlayed = Image.fromarray(background.frame)или что-то вроде:

overlayed = Frame()
overlayed.load_from_array(background.frame)

Или так же, background.save("save path")как это берет непосредственно из внутренней альфа-композицииself.frame переменной .

Вы можете прочитать файл и найти какие - то другие функции хорошо с этой реализацией I закодированной как и методы get_rgb_frame_array, resize_by_ratio, resize_to_resolution, rotate, gaussian_blur, transparency, vignetting:)

Возможно, вы захотите удалить resolve_pendingметод, так как он специфичен для этого проекта.

Рад, что я помог вам, обязательно ознакомьтесь с репозиторием проекта, о котором я говорю, этот вопрос и тема очень помогли мне в разработке :)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.