Title: Blur an area on an image in Python
My post Pixelate and area on an image in Python shows how you can pixelate an area on an image to protect someone's privacy. This post protects privacy by letting you blur an area like a person's face.
Approach
Run the program and use the File menu to open an image. Use the Blur menu to set the area's shape (Ellipse or Rectangle), blur radius (the thickness of the area along the shape's edges that is partially transparent, more on this shortly), and the size of the blurring filter. Then click and drag to select the area you want to blur.
The program copies part of the image around the area that you selected and applies a blurring filter to blur the copy. See my post Use image filters to blur and sharpen images, and to detect edges in Python to learn how the filter works and what the kernel's size means.
Next, the program overlays the blurred image onto the original image. To make the edges of the blurred area blend in smoothly, the program uses a mask image that defines alpha (opacity) color components for the blurred image's pixels. The pixels near the selected area's edges are increasingly transparent as shown in the picture on the right. To make the mask, the program uses the draw_blurred_shape function described in my post Draw shapes with translucent edges with PIL in Python.
blur_area
The following blur_area function performs the steps described in the "Approach" section. It copies part of the original image, uses a filter to blur it, creates the mask, and pastes the blurred area onto the original image.
def blur_area(image, shape_type, radius, filter_size, xmin, ymin, xmax, ymax):
'''Pixelate the indicated area.'''
# Expand the selected area to include the blurred area plus
# a margin so the filter will fit.
margin = filter_size // 2
xmin -= radius + margin
ymin -= radius + margin
xmax += radius + margin
ymax += radius + margin
# Copy the image's selected area.
rect = (xmin, ymin, xmax, ymax)
rect_image = image.crop(rect)
# Blur the area.
rect_image = Filter.box_filter(filter_size).apply(rect_image)
# Make a mask image.
wid = rect_image.width
hgt = rect_image.height
mask = Image.new('RGBA', (wid, hgt), color=None)
draw_blurred_shape(mask, margin, margin, wid - margin, hgt - margin,
shape_type, radius)
# Debgging: Save the mask.
if DEBUG:
mask.save('mask.png')
# Copy the blurred area back onto the original image using the mask.
image.paste(rect_image, (xmin, ymin), mask)
# Debugging: Outline the selected area and the expanded area.
if DEBUG:
dr = ImageDraw.Draw(image)
if shape_type == 'Rectangle':
dr.rectangle(rect, outline='yellow')
else:
dr.ellipse(rect, outline='yellow')
The function first sets variable margin to half of the kernel's size. If you read my post Use image filters to emboss images in Python, you'll learn that you cannot apply a filter all the way up to the edges of an image. When you center a kernel over the pixels at the image's edge, part of the kernel hangs off of the image so the result isn't defined. To make it possible to apply the filter to the entirety of the selected area, the blur_area function adds the margin to the area.
Next, the code uses the image's crop method to make a copy of the enlarged area and applies a blurring filter to the copy. (See Use image filters to blur and sharpen images, and to detect edges in Python.)
The function then uses the draw_blurred_shape function (see Draw shapes with translucent edges with PIL in Python) to create a mask image with blurry edges. The coordinates passed into the function do not include the margin, so the blurry shape does not include the marginal area where the kernel is undefined. That means the marginal areas are completely transparent.
Finally, the code pastes the blurred copy onto the original image using the mask image.
If you set the DEBUG value defined at the top of the program to True, the program draws the area you selected in red and the area expanded with the margin in yellow as shown in the picture on the right.
Conclusion
This program gives you another option for obscuring parts of an image. Use larger blur radii to make the result blend into the original image over a wider area. Use larger kernel sizes to make the area blurrier. Note that larger kernels and larger areas take longer.
Download the example to experiment with it and to see additional details.
|