Jak połączyć przezroczysty obraz png z innym obrazem za pomocą PIL

151

Mam przezroczysty obraz png „foo.png” i otworzyłem inny obraz za pomocą

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

teraz potrzebuję scalenia foo.png z foo2.png.

(foo.png zawiera jakiś tekst i chcę wydrukować ten tekst na foo2.png)

Arackna
źródło
71
Nie używaj ;na końcu swoich poleceń w Pythonie: jest brzydki ...
nosklo
6
Będę o tym pamiętać, dzięki !!
Arackna,

Odpowiedzi:

288
import Image

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

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

Pierwszy parametr .paste()to obraz do wklejenia. Drugi to współrzędne, a tajemniczy sos to trzeci parametr. Wskazuje maskę, która zostanie użyta do wklejenia obrazu. Jeśli przekazujesz obraz z przezroczystością, kanał alfa jest używany jako maska.

Sprawdź dokumenty .

nosklo
źródło
6
Aby upewnić się, że pierwszy plan zawiera przezroczystość we wszystkich przypadkach, użyj foreground.convert('RGBA')parametru maski.
Mark Ransom
2
Dzięki. Brakowało mi trzeciego parametru.
Silouane Gerin,
13
DostajęValueError: bad transparency mask
Deniz Ozger
2
Sekretny sos był smaczny
AFP_555
3
@DenizOzger Aby naprawić ValueError: bad transparency maskużyciebg.paste(fg, (0, 0), fg.convert('RGBA'))
Mingwei Samuel
66

Image.pastenie działa zgodnie z oczekiwaniami, gdy obraz tła również zawiera przezroczystość. Musisz użyć prawdziwego Alpha Compositing .

Poduszka 2.0 zawiera alpha_compositefunkcję, która to robi.

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

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

EDYCJA: Oba obrazy muszą być typu RGBA. Więc musisz zadzwonić, convert('RGBA')jeśli są paletowane, itp. Jeśli tło nie ma kanału alfa, możesz użyć zwykłej metody wklejania (która powinna być szybsza).

olt
źródło
Po prostu użyłem metody paste () do nałożenia jednego półprzezroczystego obrazu na inny za pomocą PIL i działało zgodnie z oczekiwaniami. W jaki sposób nie działa zgodnie z oczekiwaniami?
Peter Hansen,
3
@PeterHansen, funkcja paste () nie działa zgodnie z oczekiwaniami, „gdy obraz tła również zawiera przezroczystość”.
homm
1
@PeterHansen Jest przykład: github.com/python-pillow/Pillow/issues/…
homm
@homm dzięki. To było tak dawno temu, że nie pamiętam, czego próbowałem. Wygląda na to, że przegapiłem część, którą zacytowałeś, dotyczącą obrazu tła, który również jest przezroczysty.
Peter Hansen
4
Ja też dostaję ValueError: image has wrong made@DenizOzger
digitaldavenyc
48

Jak już zauważył olt , Image.pastenie działa poprawnie, gdy źródło i miejsce docelowe zawierają alfę.

Rozważ następujący scenariusz:

Dwa obrazy testowe, oba zawierają alfa:

wprowadź opis obrazu tutaj wprowadź opis obrazu tutaj

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

Komponowanie obrazu za pomocą Image.paste:

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

tworzy następujący obraz (część alfa nałożonych czerwonych pikseli jest całkowicie pobierana z drugiej warstwy. Piksele nie są mieszane prawidłowo):

wprowadź opis obrazu tutaj

Komponowanie obrazu za pomocą Image.alpha_composite:

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

tworzy następujący (poprawny) obraz:

wprowadź opis obrazu tutaj

P.Melch
źródło
1
Dzięki za zrzuty ekranu! Naprawdę pomaga!
Viet
1
Ale alpha_compositenie możesz ustawić przesunięcia, czy mógłbyś podać przykład całkowitego zastąpienia pastefunkcji?
Mithril
3
Myślę, że musiałbyś utworzyć nowy pusty obraz o tym samym rozmiarze co obraz garget, wkleić warstwę we właściwej pozycji i użyć alpha_compositing, aby połączyć nowy obraz z obrazem docelowym.
P.Melch,
11

Można też zastosować blendowanie:

im1 = Image.open("im1.png")
im2 = Image.open("im2.png")
blended = Image.blend(im1, im2, alpha=0.5)
blended.save("blended.png")
nvd
źródło
1
Ten ascetycznie zadziałał dla mnie. Obrazy muszą mieć dokładnie ten sam rozmiar, ale jest w porządku. Funkcja wklejania mi nie
wyszła
2
„ValueError: images not match”
Schütze
2
Możliwe, że mają różne wymiary. Może być konieczne skalowanie lub przycięcie jednego z nich.
nvd
2
@ Schütze zobacz komentarz nvd, ponieważ on / ona nie pingował (używając @blahblah) ciebie
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
陈旭 周 记
źródło
2
Cześć, czy możesz dodać trochę więcej kontekstu do swojej odpowiedzi? W przeciwnym razie wnioskodawca prawdopodobnie nie dowie się „dlaczego” za tym stoi.
jimf
0

Miałem podobne pytanie i trudno było znaleźć odpowiedź. Poniższa funkcja umożliwia wklejenie obrazu z parametrem przezroczystości do innego obrazu z określonym przesunięciem.

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()
zawietrzny
źródło
ValueError: images do not match
lllllllllllll
0

Skończyło się na kodowaniu sobie sugestii tego komentarza że sam kodowałem złożoną przez użytkownika @ P.Melch i zasugerowaną przez @Mithril w projekcie, nad którym pracuję.

Zakodowałem również poza granicami bezpieczeństwa, oto kod do tego . (Połączyłem konkretne zatwierdzenie, ponieważ w przyszłości to repozytorium może się zmienić)

Uwaga: Spodziewam się tablic numpy z obrazów, takich np.array(Image.open(...))jak wejścia A i B copy_fromoraz te połączone overlayargumenty funkcji .

Zależnościami są funkcja tuż przed nią, copy_frommetoda i tablice numpy jako zawartość obrazu PIL do wycinania.

Chociaż plik jest bardzo zorientowany na klasy, jeśli chcesz użyć tej funkcji overlay_transparent, pamiętaj o zmianie nazwy plikuself.frame tablicę numpy obrazu tła.

Lub możesz po prostu skopiować cały plik (prawdopodobnie usunąć niektóre importy i Utilsklasę) i wejść w interakcję z tą klasą Frame w następujący sposób:

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

Następnie masz swoją background.framejako nakładaną i skomponowaną tablicę alfa, możesz pobrać z niej obraz PIL za pomocą overlayed = Image.fromarray(background.frame)lub czegoś takiego:

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

Lub po prostu background.save("save path")tak, jak pobiera się bezpośrednio ze złożonej self.framezmiennej wewnętrznej alfa .

Można odczytać pliku i znaleźć jakieś inne funkcje ładny z tej implementacji I kodowanej podobnie jak metody get_rgb_frame_array, resize_by_ratio, resize_to_resolution, rotate, gaussian_blur, transparency, vignetting:)

Prawdopodobnie chciałbyś usunąć resolve_pending metodę, ponieważ jest ona specyficzna dla tego projektu.

Cieszę się, że pomogłem, koniecznie sprawdź repozytorium projektu o którym mówię, to pytanie i wątek bardzo mi pomogły w rozwoju :)

Tremeschin
źródło