Cách hợp nhất hình ảnh png trong suốt với hình ảnh khác bằng PIL


151

Tôi có một hình ảnh png trong suốt "foo.png" và tôi đã mở một hình ảnh khác với

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

bây giờ những gì tôi cần là hợp nhất foo.png với foo2.png.

(foo.png chứa một số văn bản và tôi muốn in văn bản đó trên foo2.png)


71
Đừng sử dụng ;ở cuối lệnh của bạn trong python: Thật xấu xí ...
nosklo

6
Tôi sẽ giữ nó trong tâm trí của tôi, cảm ơn !!
Arackna

Câu trả lời:


288
import Image

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

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

Tham số đầu tiên .paste()là hình ảnh để dán. Thứ hai là tọa độ, và nước sốt bí mật là tham số thứ ba. Nó chỉ ra một mặt nạ sẽ được sử dụng để dán hình ảnh. Nếu bạn vượt qua một hình ảnh có độ trong suốt, thì kênh alpha được sử dụng làm mặt nạ.

Kiểm tra tài liệu .


6
Để đảm bảo tiền cảnh chứa độ trong suốt trong mọi trường hợp, hãy sử dụng foreground.convert('RGBA')cho tham số mặt nạ.
Đánh dấu tiền chuộc

2
Cảm ơn. Tôi đã quá thiếu tham số thứ ba.
Silouane Gerin

13
Tôi đang nhận đượcValueError: bad transparency mask
Deniz Ozger 3/03/2016

2
Nước sốt bí mật rất ngon
AFP_555

3
@DenizOzger Để khắc phục ValueError: bad transparency maskviệc sử dụngbg.paste(fg, (0, 0), fg.convert('RGBA'))
Mingwei Samuel

66

Image.pastekhông hoạt động như mong đợi khi hình nền cũng chứa độ trong suốt. Bạn cần sử dụng Alpha Compositing thực sự .

Gối 2.0 chứa một alpha_compositechức năng thực hiện điều này.

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

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

EDIT: Cả hai hình ảnh cần phải thuộc loại RGBA. Vì vậy, bạn cần gọi convert('RGBA')nếu chúng bị mờ, vv .. Nếu nền không có kênh alpha, thì bạn có thể sử dụng phương pháp dán thông thường (nên nhanh hơn).


Tôi chỉ sử dụng paste () để phủ một hình ảnh bán trong suốt lên một hình khác, với PIL và nó hoạt động như tôi mong đợi. Theo cách nào nó không hoạt động như bạn mong đợi?
Peter Hansen

3
@PeterHansen, paste () không hoạt động như mong đợi "khi hình nền cũng chứa độ trong suốt".
homm

1
@PeterHansen Có một ví dụ: github.com/python-pfl/Pvel/issues/ mẹo
homm

@ xin cảm ơn. Đó là rất lâu trước đây tôi không có ký ức về những gì tôi đã cố gắng. Có vẻ như tôi đã bỏ lỡ phần bạn trích dẫn về hình nền cũng có độ trong suốt.
Peter Hansen

4
Tôi nhận được ValueError: image has wrong madecũng @DenizOzger
digitaldavenyc

48

Như olt đã chỉ ra, Image.pastekhông hoạt động đúng, khi cả nguồn đích đều chứa alpha.

Hãy xem xét kịch bản sau đây:

Hai hình ảnh thử nghiệm, cả hai đều chứa alpha:

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

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

Tổng hợp hình ảnh bằng cách sử dụng Image.pastenhư vậy:

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

tạo ra hình ảnh sau (phần alpha của các pixel màu đỏ được phủ hoàn toàn được lấy từ lớp thứ 2. Các pixel không được trộn chính xác):

nhập mô tả hình ảnh ở đây

Tổng hợp hình ảnh bằng cách sử dụng Image.alpha_compositenhư vậy:

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

tạo ra hình ảnh (chính xác) sau đây:

nhập mô tả hình ảnh ở đây


1
Cảm ơn các ảnh chụp màn hình! Thực sự giúp!
Việt

1
Nhưng alpha_compositekhông thể đặt bù, bạn có muốn đưa ra một ví dụ để thay thế hoàn toàn pastechức năng không?
Mithril

3
Tôi đoán bạn sẽ phải tạo một hình ảnh trống mới có cùng kích thước với hình ảnh garget, dán lớp ở vị trí thích hợp và sử dụng alpha_compositing để trộn hình ảnh mới trên hình ảnh mục tiêu.
P.Melch

11

Người ta cũng có thể sử dụng pha trộn:

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

1
Điều này khổ hạnh làm việc cho tôi. Các hình ảnh phải có cùng kích thước, nhưng nó là ok. Chức năng dán không hoàn toàn cắt nó cho tôi ...
Liviu Sosu

2
'ValueError: hình ảnh không khớp'
Schütze

2
Có thể, chúng có kích thước khác nhau. Bạn có thể cần phải mở rộng quy mô hoặc cắt một trong số đó.
nvd

2
@ Schütze xem bình luận của nvd vì anh ấy / cô ấy không ping (sử dụng @blahblah) bạn
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
Xin chào, bạn có thể thêm một chút bối cảnh vào câu trả lời của bạn không? Mặt khác, người yêu cầu không có khả năng tìm hiểu "lý do" đằng sau nó.
jimf

0

Có một câu hỏi tương tự và gặp khó khăn khi tìm câu trả lời. Chức năng sau đây cho phép bạn dán một hình ảnh với tham số trong suốt trên một hình ảnh khác ở một độ lệch cụ thể.

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
lllllllllll

0

Tôi đã kết thúc việc tự mã hóa đề xuất của bình luận nàyCuối cùng do người dùng @ P.Melch đưa ra và được đề xuất bởi @Mithril trong một dự án tôi đang thực hiện.

Tôi cũng đã mã hóa ra khỏi giới hạn an toàn, đây là mã cho nó . (Tôi đã liên kết một cam kết cụ thể vì mọi thứ có thể thay đổi trong tương lai của kho lưu trữ này)

Lưu ý: Tôi mong đợi các mảng numpy từ các hình ảnh giống np.array(Image.open(...))như các đầu vào A và B từ copy_fromvà các overlayđối số chức năng được liên kết này .

Các phụ thuộc là hàm ngay trước nó, copy_fromphương thức và mảng numpy như nội dung PIL Image để cắt.

Mặc dù tệp được định hướng rất đẳng cấp, nhưng nếu bạn muốn sử dụng chức năng đó overlay_transparent, hãy nhớ đổi tênself.frame mảng numpy hình ảnh nền của bạn.

Hoặc bạn chỉ có thể sao chép toàn bộ tệp (có thể xóa một số nhập và Utilslớp) và tương tác với lớp Khung này như sau:

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

Sau đó, bạn có background.framemảng tổng hợp lớp phủ và alpha, bạn có thể nhận được hình ảnh PIL từ nó với overlayed = Image.fromarray(background.frame)hoặc đại loại như:

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

Hoặc chỉ cần background.save("save path")lấy trực tiếp từ nội bộ tổng hợp alphaself.frame biến .

Bạn có thể đọc các tập tin và tìm thấy một số chức năng tuyệt vời khác với thi này tôi mã hóa như các phương pháp get_rgb_frame_array, resize_by_ratio, resize_to_resolution, rotate, gaussian_blur, transparency,vignetting :)

Bạn có thể muốn loại bỏ resolve_pending phương thức đó là cụ thể cho dự án đó.

Rất vui nếu tôi đã giúp bạn, hãy chắc chắn kiểm tra repo của dự án mà tôi đang nói đến, câu hỏi và chủ đề này đã giúp tôi rất nhiều về sự phát triển :)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.