So führen Sie mit PIL ein transparentes PNG-Bild mit einem anderen Bild zusammen

151

Ich habe ein transparentes PNG-Bild "foo.png" und ich habe ein anderes Bild mit geöffnet

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

Jetzt muss ich foo.png mit foo2.png zusammenführen.

(foo.png enthält Text und ich möchte diesen Text auf foo2.png drucken.)

Arackna
quelle
71
Verwenden Sie nicht ;am Ende Ihrer Befehle in Python: Es ist hässlich ...
Nosklo
6
Ich werde das im Kopf behalten, danke !!
Arackna

Antworten:

288
import Image

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

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

Der erste Parameter .paste()ist das einzufügende Bild. Zweitens sind Koordinaten, und die geheime Sauce ist der dritte Parameter. Es zeigt eine Maske an , die zum Einfügen des Bildes verwendet wird. Wenn Sie ein Bild mit Transparenz übergeben, wird der Alphakanal als Maske verwendet.

Überprüfen Sie die Dokumente .

nosklo
quelle
6
Verwenden Sie foreground.convert('RGBA')für den Maskenparameter, um sicherzustellen, dass der Vordergrund in allen Fällen Transparenz enthält .
Mark Ransom
2
Vielen Dank. Mir fehlte auch der dritte Parameter.
Silouane Gerin
13
Ich bekommeValueError: bad transparency mask
Deniz Ozger
2
Die geheime Sauce war lecker
AFP_555
3
@ DenizOzger Um die ValueError: bad transparency maskVerwendung zu behebenbg.paste(fg, (0, 0), fg.convert('RGBA'))
Mingwei Samuel
66

Image.pastefunktioniert nicht wie erwartet, wenn das Hintergrundbild auch Transparenz enthält. Sie müssen echtes Alpha Compositing verwenden .

Pillow 2.0 enthält eine alpha_compositeFunktion, die dies tut.

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

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

BEARBEITEN: Beide Bilder müssen vom Typ RGBA sein. Sie müssen also aufrufen, convert('RGBA')wenn sie palettiert sind usw. Wenn der Hintergrund keinen Alphakanal hat, können Sie die reguläre Einfügemethode verwenden (die schneller sein sollte).

olt
quelle
Ich habe gerade paste () verwendet, um ein halbtransparentes Bild mit PIL auf ein anderes zu legen, und es hat wie erwartet funktioniert. Inwiefern funktioniert es nicht wie erwartet?
Peter Hansen
3
@PeterHansen, paste () funktioniert nicht wie erwartet, "wenn das Hintergrundbild auch Transparenz enthält".
homm
1
@ PeterHansen Es gibt Beispiel: github.com/python-pillow/Pillow/issues/…
homm
@homm danke. Das ist so lange her, dass ich mich nicht daran erinnern kann, was ich versucht habe. Es ist wahrscheinlich, dass ich den von Ihnen zitierten Teil über das Hintergrundbild mit Transparenz verpasst habe.
Peter Hansen
4
Ich bekomme ValueError: image has wrong madeauch @DenizOzger
digitaldavenyc
48

Wie olt bereits erwähnt, Image.pastefunktioniert nicht richtig, wenn die Quelle und Ziel beider Alpha enthalten.

Stellen Sie sich das folgende Szenario vor:

Zwei Testbilder, beide enthalten Alpha:

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

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

Zusammensetzen eines Bildes mit folgendem Image.paste:

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

erzeugt das folgende Bild (der Alpha-Teil der überlagerten roten Pixel wird vollständig aus der 2. Ebene übernommen. Die Pixel werden nicht richtig gemischt):

Geben Sie hier die Bildbeschreibung ein

Zusammensetzen eines Bildes mit folgendem Image.alpha_composite:

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

erzeugt das folgende (richtige) Bild:

Geben Sie hier die Bildbeschreibung ein

P. Melch
quelle
1
Danke für die Screenshots! Hilft wirklich!
Viet
1
Aber alpha_compositekann den Offset nicht einstellen, würde es Ihnen etwas ausmachen, ein Beispiel zu geben, um die pasteFunktion vollständig zu ersetzen ?
Mithril
3
Ich denke, Sie müssten ein neues leeres Bild mit der gleichen Größe wie das Garget-Bild erstellen, die Ebene an der richtigen Position einfügen und alpha_compositing verwenden, um das neue Bild über das Zielbild zu mischen.
P. Melch
11

Man kann auch das Mischen verwenden:

im1 = Image.open("im1.png")
im2 = Image.open("im2.png")
blended = Image.blend(im1, im2, alpha=0.5)
blended.save("blended.png")
nvd
quelle
1
Dieser arbeitete asketisch für mich. Die Bilder müssen genau die gleiche Größe haben, aber es ist in Ordnung. Die Paste-Funktion hat es für mich nicht ganz ausgeschnitten ...
Liviu Sosu
2
'ValueError: Bilder stimmen nicht überein'
Schütze
2
Möglicherweise haben sie unterschiedliche Dimensionen. Möglicherweise müssen Sie eine davon skalieren oder zuschneiden.
NVD
2
@ Schütze siehe nvds Kommentar, weil er / sie nicht (mit @blahblah) Sie pingte
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
陈旭 周 记
quelle
2
Hallo, können Sie Ihrer Antwort möglicherweise etwas mehr Kontext hinzufügen? Andernfalls wird der Anforderer wahrscheinlich nicht das "Warum" dahinter erfahren.
Jimf
0

Hatte eine ähnliche Frage und hatte Schwierigkeiten, eine Antwort zu finden. Mit der folgenden Funktion können Sie ein Bild mit einem Transparenzparameter mit einem bestimmten Versatz über ein anderes Bild einfügen.

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()
Lee
quelle
ValueError: images do not match
lllllllllllll
0

Am Ende habe ich mir den Vorschlag dieses Kommentars codiert, den der Benutzer @ P.Melch gemacht und von @Mithril für ein Projekt vorgeschlagen hat, an dem ich arbeite.

Ich habe auch außerhalb der Grenzen der Sicherheit codiert, hier ist der Code dafür . (Ich habe ein bestimmtes Commit verknüpft, da sich die Dinge in der Zukunft dieses Repositorys ändern können.)

Hinweis: Ich erwarte numpy Arrays von den Bildern wie np.array(Image.open(...))die Eingänge A und B von copy_fromund diese verknüpfte Funktionoverlay .

Die Abhängigkeiten sind die Funktion direkt davor, die copy_from Methode und die Numpy-Arrays als PIL-Bildinhalt für das Schneiden.

Obwohl die Datei sehr klassenorientiert ist, müssen Sie die Funktion overlay_transparentumbenennen , wenn Sie diese Funktion verwenden möchtenself.frame klassenorientiert ist, müssen Sie das Numpy-Array in Ihr Hintergrundbild möchten.

Oder Sie können einfach die gesamte Datei kopieren (wahrscheinlich einige Importe und die UtilsKlasse entfernen ) und mit dieser Frame-Klasse wie folgt interagieren:

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

Dann haben Sie Ihr background.frameals überlagertes und Alpha-zusammengesetztes Array, Sie können ein PIL-Bild daraus erhalten mit overlayed = Image.fromarray(background.frame)oder so etwas wie:

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

Oder einfach background.save("save path")so, wie es direkt aus der Alpha-zusammengesetzten internen self.frameVariablen hervorgeht.

Sie können die Datei lesen und einige andere nette Funktionen mit dieser Implementierung ich wie die Methoden codiert finden get_rgb_frame_array, resize_by_ratio, resize_to_resolution, rotate, gaussian_blur, transparency, vignetting:)

Sie möchten wahrscheinlich die entfernen resolve_pending Methode , da dies für dieses Projekt spezifisch ist.

Ich bin froh, wenn ich dir geholfen habe, schau dir unbedingt das Repo des Projekts an, über das ich spreche. Diese Frage und dieser Thread haben mir bei der Entwicklung sehr geholfen :)

Tremeschin
quelle