วิธีผสานภาพ png โปร่งใสเข้ากับภาพอื่นโดยใช้ PIL


151

ฉันมีรูปแบบ png โปร่งใส "foo.png" และฉันเปิดภาพอื่นด้วย

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

ตอนนี้สิ่งที่ฉันต้องการคือการรวม foo.png กับ foo2.png

(foo.png มีข้อความบางส่วนและฉันต้องการพิมพ์ข้อความนั้นบน foo2.png)


71
อย่าใช้;ปลายคำสั่งของคุณในไพ ธ อน: มันน่าเกลียด ...
nosklo

6
ฉันจะเก็บมันไว้ในใจของฉันขอบคุณ !!
Arackna

คำตอบ:


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')สำหรับพารามิเตอร์หน้ากาก
Mark Ransom

2
ขอบคุณ ฉันพลาดพารามิเตอร์ที่สามมากเกินไป
Silouane Gerin

13
ฉันกำลังจะได้รับValueError: bad transparency mask
นิซโอซเกอร์

2
ซอ
สลับ

3
@DenizOzger เพื่อแก้ไขการValueError: bad transparency maskใช้งานbg.paste(fg, (0, 0), fg.convert('RGBA'))
Mingwei Samuel

66

Image.pasteไม่ทำงานอย่างที่คาดไว้เมื่อภาพพื้นหลังมีความโปร่งใส คุณจำเป็นต้องใช้จริงอัลฟา Compositing

Pillow 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 และทำงานได้ตามที่คาดไว้ มันไม่ทำงานตามที่คุณคาดหวัง
Peter Hansen

3
@PeterHansen, paste () ไม่ทำงานอย่างที่คาดไว้ "เมื่อภาพพื้นหลังมีความโปร่งใส"
homm

1
@PeterHansen มีตัวอย่าง: github.com/python-pillow/Pillow/issues/…
homm

@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
ฉันเดาว่าคุณจะต้องสร้างภาพเปล่าใหม่ที่มีขนาดเท่ากับภาพ Garget วางเลเยอร์ไว้ในตำแหน่งที่เหมาะสมและใช้ 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
อันนี้ใช้ได้ผลสำหรับฉัน ภาพต้องมีขนาดเท่ากันทุกประการ แต่ก็โอเค ฟังก์ชั่นวางไม่ตัดมันค่อนข้างสำหรับฉัน ...
Liviu Sosu

2
'ValueError: รูปภาพไม่ตรงกัน'
Schütze

2
อาจมีขนาดต่างกัน คุณอาจต้องปรับขนาดหรือครอบตัดอย่างใดอย่างหนึ่ง
nvd

2
@ Schützeดูความคิดเห็นของ nvd เพราะเขา / เธอไม่ได้ ping (ใช้ @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 ในโครงการที่ฉันกำลังทำงานอยู่

ฉันออกรหัสความปลอดภัยขอบเขตเช่นกันนี่คือรหัสสำหรับมัน (ฉันเชื่อมโยงการมอบหมายที่เฉพาะเจาะจงเพราะสิ่งต่าง ๆ สามารถเปลี่ยนแปลงได้ในอนาคตของที่เก็บนี้)

หมายเหตุ: ฉันคาดหวังอาร์เรย์ numpy จากภาพเช่นnp.array(Image.open(...))เป็นอินพุต A และ B จากcopy_fromและoverlayข้อโต้แย้งฟังก์ชั่นที่เชื่อมโยงนี้

การพึ่งพาคือฟังก์ชันที่อยู่ก่อนหน้าcopy_fromวิธีการและอาร์เรย์ที่มีจำนวนมากในรูปแบบ PIL Image สำหรับการแบ่งส่วน

แม้ว่าไฟล์นั้นจะเป็นแบบคลาสสิก แต่ถ้าคุณต้องการใช้ฟังก์ชั่นoverlay_transparentนั้นต้องแน่ใจว่าได้เปลี่ยนชื่อเป็นself.frameอาเรย์ numpy ภาพพื้นหลังของคุณ

หรือคุณสามารถคัดลอกไฟล์ทั้งหมด (อาจลบการนำเข้าและ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ตัวแปรภายในที่มีการรวมตัวของอัลฟา

คุณสามารถอ่านไฟล์และพบบางฟังก์ชั่นที่ดีอื่น ๆ ที่มีการดำเนินงานนี้ฉันรหัสเช่นวิธีการget_rgb_frame_array, resize_by_ratio, resize_to_resolution, rotate, gaussian_blur, transparency, vignetting:)

คุณอาจต้องการลบresolve_pendingวิธีการเฉพาะสำหรับโครงการนั้น

ดีใจที่ฉันช่วยคุณตรวจสอบ repo ของโครงการที่ฉันกำลังพูดถึงคำถามและหัวข้อนี้ช่วยฉันได้มากในการพัฒนา :)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.