I'm writing a script to detect faces and blur out everything but the face.
I find the faces using Haar Cascades, then create a mask for with circles where the faces are. Then I add them together. This works fine for adding where the divide is absolute but I can't work out how to have the blur taper off without a blunt line. Blurring the mask just creates an ugly line where the tapering should be.
import numpy as np
import cv2
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')
original_image = cv2.imread('person.jpg')
gray_original_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)
# mask
# detect faces and create mask
mask = np.full(
(original_image.shape[0], original_image.shape[1], 1), 0, dtype=np.uint8)
faces = face_cascade.detectMultiScale(gray_original_image, 1.3, 5)
face_areas = []
for (x, y, w, h) in faces:
face_areas.append(([x, y, w, h], original_image[y:y+h, x:x+w]))
center = (x + w // 2, y + h // 2)
radius = max(h, w) // 2
cv2.circle(mask, center, radius, (255), -1)
# blur original image
kernel = np.ones((5, 5), np.float32) / 25
blurred_image = cv2.filter2D(original_image, -1, kernel)
# blur mask to get tapered edge
mask = cv2.filter2D(mask, -1, kernel)
# composite blurred and unblurred faces
mask_inverted = cv2.bitwise_not(mask)
background = cv2.bitwise_and(
blurred_image, blurred_image, mask=mask_inverted)
foreground = cv2.bitwise_and(original_image, original_image, mask=mask)
composite = cv2.add(background, foreground)
cv2.imshow('composite', composite)
cv2.waitKey(0)
cv2.destroyAllWindows()
Desired result (no obvious line between blurred/non blurred)