Everyone's longing, world champion "Mr. Satan". I made an app that can be transformed into that "Mr. Satan". If you wear the characteristic eyebrows, beard and afro hair, you are also "Mr. Satan"!
Technically, we use a library called face_recognition to get the coordinates of various parts of the face, and based on that, we calculate the position and size of the eyebrows, beard, and afro and draw them.
Face Recognition is the world's simplest face recognition library that can recognize and manipulate faces.
Recognize and manipulate faces from Python or from the command line with the world's simplest face recognition library.
To use it, first install it with pip.
$ pip install opencv-python
$ pip install opencv-contrib-python
$ pip install cmake
$ pip install face_recognition
As a test, try to get the face parts using the image below.
import face_recognition
import cv2
F = "image.jpg "
image = face_recognition.load_image_file(F)
face_landmarks_list = face_recognition.face_landmarks(image)
print(face_landmarks_list)
I got the coordinates of each part. Let's plot the obtained coordinates on the actual image.
bgr = cv2.imread(F)
for face_landmarks in face_landmarks_list:
for facial_feature in face_landmarks.keys():
for i in range(len(face_landmarks[facial_feature])):
cv2.drawMarker(bgr, face_landmarks[facial_feature][i],
color=(255, 0, 0), markerType=cv2.MARKER_CROSS, thickness=1)
cv2.imshow('', bgr)
cv2.waitKey(0)
cv2.destroyAllWindows()
You can see that it is recognized correctly.
$ pip install opencv-python
$ pip install opencv-contrib-python
$ pip install cmake
$ pip install face_recognition
import face_recognition
import cv2
from PIL import Image
import numpy as np
#Maximum vertical and horizontal width of the image
MAX_IMAGE_WIDTH = 10000
MAX_IMAGE_HEIGHT = 10000
class CvOverlayImage(object):
"""
[summary]
Overlay the specified image on the OpenCV format image
"""
def __init__(self):
pass
@classmethod
def overlay(
cls,
cv_background_image,
cv_overlay_image,
point,
):
"""
[summary]
Overlay the specified image on the OpenCV format image
Parameters
----------
cv_background_image : [OpenCV Image]
cv_overlay_image : [OpenCV Image]
point : [(x, y)]
Returns : [OpenCV Image]
"""
overlay_height, overlay_width = cv_overlay_image.shape[:2]
#Convert OpenCV format images to PIL format(Including α value)
#background image
cv_rgb_bg_image = cv2.cvtColor(cv_background_image, cv2.COLOR_BGR2RGB)
pil_rgb_bg_image = Image.fromarray(cv_rgb_bg_image)
pil_rgba_bg_image = pil_rgb_bg_image.convert('RGBA')
#Overlay image
cv_rgb_ol_image = cv2.cvtColor(cv_overlay_image, cv2.COLOR_BGRA2RGBA)
pil_rgb_ol_image = Image.fromarray(cv_rgb_ol_image)
pil_rgba_ol_image = pil_rgb_ol_image.convert('RGBA')
# composite()Since images of the same size are required, prepare images for compositing
pil_rgba_bg_temp = Image.new('RGBA', pil_rgba_bg_image.size,
(255, 255, 255, 0))
#Specify coordinates and superimpose
pil_rgba_bg_temp.paste(pil_rgba_ol_image, point, pil_rgba_ol_image)
result_image = \
Image.alpha_composite(pil_rgba_bg_image, pil_rgba_bg_temp)
#Convert to OpenCV format image
cv_bgr_result_image = cv2.cvtColor(
np.asarray(result_image), cv2.COLOR_RGBA2BGRA)
return cv_bgr_result_image
def GetPosi(posi_name):
"""
[summary]
Get the coordinates of the specified face part
Parameters
----------
posi_name : [str]
Returns : [left_X、right_X, Top_Y, Bottom_Y]
"""
for face_landmarks in face_landmarks_list:
minX = MAX_IMAGE_WIDTH
maxX = 0
minY = MAX_IMAGE_HEIGHT
maxY = 0
for i in range(len(face_landmarks[posi_name])):
if face_landmarks[posi_name][i][0] < minX:
minX = face_landmarks[posi_name][i][0]
if face_landmarks[posi_name][i][0] > maxX:
maxX = face_landmarks[posi_name][i][0]
if face_landmarks[posi_name][i][1] < minY:
minY = face_landmarks[posi_name][i][1]
if face_landmarks[posi_name][i][1] > maxY:
maxY = face_landmarks[posi_name][i][1]
return [minX, maxX, minY, maxY]
#File name definition
F = "sample.jpg "
#Get face landmarks from images
image_fl = face_recognition.load_image_file(F)
face_landmarks_list = face_recognition.face_landmarks(image_fl)
#Get the coordinates of each part
eye_r = GetPosi('right_eye')
eye_l = GetPosi('left_eye')
mouse = GetPosi('top_lip')
nose = GetPosi('nose_tip')
chin = GetPosi('chin')
#Calculate eyebrow width and whiskers width from the acquired coordinates
brow_h = int((eye_r[3] - eye_r[2]) * 2)
face_w = chin[1] - chin[0]
beard_h = int((mouse[2] - nose[2]) * 0.7)
beard_w = int((face_w - (mouse[1] - mouse[0])) * 0.2)
beard_h2 = int((chin[3] - mouse[2]) * 0.6)
beard_h3 = int((chin[3] - mouse[2]) * 0.3)
scale = int(face_w / 20)
scale2 = scale * 2
#Calculate the location of the afro image(There is fine adjustment because it is not symmetrical)
hair_w = int(face_w * 1.83)
hair_h = int(hair_w * 0.64)
hair_x = int(chin[0] - (hair_w / 2 - face_w / 2) + scale * 1.5)
hair_y = eye_l[2] - hair_h
#Eyebrow / beard coordinate calculation
eyeb_r = np.array(
[
[eye_r[0] - scale2, eye_r[2] - brow_h],
[eye_r[1] + scale2, eye_r[2] - brow_h - scale2],
[eye_r[1] + scale2, eye_r[2] - scale * 2] ,
[eye_r[0] - scale2, eye_r[2]]
]
)
eyeb_l = np.array(
[
[eye_l[0] - scale2, eye_l[2] - brow_h - scale2],
[eye_l[1] + scale2, eye_l[2] - brow_h],
[eye_l[1] + scale2, eye_l[2]] ,
[eye_l[0] - scale2, eye_l[2] - scale * 2]
]
)
beard_c = np.array(
[
[mouse[0] - scale, mouse[2] - beard_h],
[mouse[1] + scale, mouse[2] - beard_h],
[mouse[1] + scale, mouse[2] - 0] ,
[mouse[0] - scale, mouse[2] - 0]
]
)
beard_l = np.array(
[
[mouse[0] - beard_w, mouse[2] - beard_h - scale],
[mouse[0] - 5, mouse[2] - beard_h],
[mouse[0] - 5, mouse[2] + beard_h2],
[mouse[0] - beard_w, mouse[2] + beard_h3]
]
)
beard_r = np.array(
[
[mouse[1] + 5, mouse[2] - beard_h],
[mouse[1] + beard_w, mouse[2] - beard_h - scale],
[mouse[1] + beard_w, mouse[2] + beard_h3],
[mouse[1] + 5, mouse[2] + beard_h2]
]
)
#Read files with OpenCV
image = cv2.imread(F)
#Eyebrows / beard / drawing process
cv2.fillConvexPoly(image, points =eyeb_r, color=(0, 0, 0))
cv2.fillConvexPoly(image, points =eyeb_l, color=(0, 0, 0))
cv2.fillConvexPoly(image, points =beard_c, color=(0, 0, 0))
cv2.fillConvexPoly(image, points =beard_l, color=(0, 0, 0))
cv2.fillConvexPoly(image, points =beard_r, color=(0, 0, 0))
#Overlay display of Afro image
cv_background_image = image
cv_overlay_image = cv2.imread(
"head.png ",
cv2.IMREAD_UNCHANGED) # IMREAD_Specify UNCHANGED and read with α
cv_overlay_image = cv2.resize(cv_overlay_image, (hair_w, hair_h))
point = (hair_x, hair_y)
image = CvOverlayImage.overlay(cv_background_image, cv_overlay_image, point)
#Image drawing
cv2.imshow("image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
This is the Afro image used. The background is transparent. Please set it as head.png and put it in the working folder.
At the moment, only the front image is supported. Face Recognition gets the coordinates with a nice feeling, so I made it with a little processing. Some of the output was interesting personally, but I gave up because of the portrait right. I hope you can play with various images.
** [OpenCV] [Python] Draw an image with transparency on top of the image **
Recommended Posts