简体   繁体   中英

How can I overlay one image over another so that dark background is transparent?

I have 2 images, test1.jpg and test2.jpg that are RGB images. They have been converted from a 2D numpy array so they are monochrome images. They have the same shape. When I use the paste function, I only see one of the images instead of both.

Here are the test1 and test2 jpgs:

测试1

测试2 .

This is what I get after doing test1.paste(test2) and test1.save('final.jpg') :

粘贴结果

Why is it only showing test2?

Here is my code:

im1 = Image.open('test1.jpg')
im2 = Image.open('test2.jpg')
im1.paste(im2)
im1.save('final.jpg')

You simply need to choose the lighter of your two images at each point with PIL Channel Operations :

from PIL import Image, ImageChops

im1 = Image.open('test1.jpeg')
im2 = Image.open('test2.jpeg')

# Choose lighter of the two images at each pixel location
combined = ImageChops.lighter(im1,im2)

在此处输入图像描述


Note that you could use paste() as you originally intended, but that it will paste all the black as well as the white pixels from image2 over image1 . In order to avoid that, you would need to make a mask and only paste where image2 is non-zero. That might look like this:

im1 = Image.open('test1.jpeg')
im2 = Image.open('test2.jpeg')

# Make greyscale mask from image2
mask = im2.convert('L')
mask = mask.point(lambda i: 255 if i>0 else 0)

# Paste image2 into image1 only where image2 has non-black content
im1.paste(im2, mask=mask)

I just think the ImageChops.lighter() method is simpler.


Note that these two methods will give subtly different results. For example, if a pixel is 192 in image1 and 67 in image2 , the ImageChops.lighter() method will result in 192, whereas the paste() method will see there is something in image2 , and therefore give you the 67. Your choice!

paste is the wrong tool for this job, because it completely replaces the original image with the image you're pasting. It appears you wanted something closer to the blend function which produces a mix of both images. Unfortunately this has the side effect of darkening the image, because white blended with black becomes a middle gray; you'll probably want to double the values to compensate.

final = Image.blend(test1, test2, 0.5)
final = Image.eval(final, lambda x: 2*x))

One solution would be to use openCV instead of PIL. OpenCV's imagery is identical to a 2D numpy array, which means you can instead just use basic matrix addition to produce a combined image given "black" pixels are just 0.

import cv2 as cv

im1 = cv.imread('test1.jpg')
im2 = cv.imread('test2.jpg')

im3 = im1 + im2
cv.imwrite('test3.jpg', im3)

The black pixels remain black, as you're adding 0 to 0, while the filled pixels have the filled values of the two images combined (in this case, 0 + a maximum of 255 given no overlap between the two images)

The resulting image:

提供的测试图像的组合形式

In the case of overlapping non-zero pixels, you may want to apply a 255 ceiling to the arrays, or instead normalize the combined image by the new maximum if that is preferred for your use case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM