Reputation: 55
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:
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')
Upvotes: 4
Views: 728
Reputation: 207630
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!
Upvotes: 5
Reputation: 96
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.
Upvotes: 1
Reputation: 308346
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))
Upvotes: 2