Title: Use a mask to overlay one image on another with Python and PIL
This example overlays an image on top of a background image while using a mask to indicate which parts of the image to replace. The following pictures show a background image, overlay image, mask, and result.
Background Image
|
Overlay Image
|
Mask Image
|
Result Image
|
The following sections describe two key pieces of the program: the perform_overlay method and the save_image_as method.
The perform_overlay Method
The key to this example is the following perform_overlay method.
def perform_overlay(self):
'''Perform the overlay.'''
# See if we have all three images.
if self.background_image is None or \
self.overlay_image is None or \
self.mask_image is None:
return
# Enable the Save menu item.
self.file_menu.entryconfig('Save As...', state='normal')
# Convert the background and overlay images to RGBA.
background = self.background_image.convert('RGBA')
overlay = self.overlay_image.convert('RGBA')
# Convert mask to grayscale.
mask = self.mask_image.convert('L')
# Perform the overlay.
background.paste(overlay, (0, 0), mask)
# Save and display the result.
self.result_image = background
self.show_image(self.result_image, self.result_canvas)
# Select the result tab.
self.notebook.select(self.result_tab)
The method first checks whether we have loaded the background, overlay, and mask images. If we have not loaded all three images, the method returns. It we have loaded all three images, the method enables the File men's Save As command.
The method for performing the overlay requires that the background and foreground images support red, green, blue, and alpha color components, so the program converts those images into RGBA format. (The alpha component represents a pixel's opacity and has value between 0 for transparent and 255 for opaque.)
We also need the mask image to be in a grayscale (L) format, so the code converts it. (The mask must have one of the formats 1, L, LA, RGBA, or RGBa.)
If a mask pixel is white (or has alpha value 255), the overlay pixel shows replaces the original image's pixel. If a mask pixel is black (or has alpha value 0), the original pixel's value remains. For values in between, the result pixel is a weighted average of the original and overlay pixel values.
(Note: Instead of using the background image's paste method, you can use the Image class's composite method. The main differences are that the paste method is a bit more flexible and the mask colors used by the two are reversed. With composite, a white mask pixel keeps the original pixel's color and a black mask pixel uses the overlay pixel's color.)
After pasting the overlay image onto the background image, the method displays the result and selects the program's result tab so you can see it.
TIP: You can use a previous example to help make the mask. Copy the background or overlay image and use an image editor to white out the parts that you want to replace. Then use the
the example Perform binary contrast enhancement with Python and PIL to make the rest of the picture black. Save the resulting mask as a PNG file or using some other lossless format if you don't want the file format to mess with your results. For example, the JPG format will probably modify some of the pixels so they won't be exactly black or white.
|
The save_image_as Method
The save_image_as method shown in the following code is a convenience method that lets the user select a file name and then saves an image into that file.
def save_image_as(self, image):
'''Save a file.'''
filetypes = (
('Image Files', '*.png;*.jpg;*.bmp;*.gif;*.tif'),
('All files', '*.*')
)
filename = fd.asksaveasfilename(filetypes=filetypes,
defaultextension='.jpg')
if len(filename) == 0:
return
# See what kind of file is it.
suffix = pathlib.Path(filename).suffix.lower()
if suffix == '.jpg' or suffix == '.jpeg':
# It's a JPG. Save in RGB format.
image.convert('RGB').save(filename)
else:
# Save in RGBA format.
image.save(filename)
This method makes a tuple of file type names and file name filters. It then uses the filedialog class's asksaveasfilename method to let the user pick a file. If the user selects a file, asksaveasfilename returns the selected file's name. If the user cancels the file selection dialog, the method returns an empty string and the save_image_as method returns.
If the user selects a file, the program saves the image in that file. Unfortunately, the JPG format does not support the RGBA format used by the program's result image.
The program uses the pathlib library to get the file's extension and checks whether it is JPG or JPEG. If the file has one of those extensions, the program converts the result image to RGB format and saves the converted image.
If the user picked a file with some other extension, the program saves the result in its RGBA format.
The PIL Image class's save method supports many other image file formats and I haven't tried them all, so it's possible that others may not support the RGBA format. If you come across another such format, you can use a similar technique to fix the program.
Download the example to see additional details and to experiment with it.
For more information image processing in Python, see my Manning liveProject Algorithm Projects with Python: Image Processing. It explain how to do things like:
|
• Rotation | • Scaling | • Stretching |
• Brightness enhancement | • Contrast enhancement | • Cropping |
• Remapping colors | • Image sharpening | • Embossing |
• Color enhancement | • Sharpening | • Gray scale |
• Black and white | • Sepia tone | • Other color scales |
|