Python teach you a line of code to put on a mask Avatar

Foreword

By the end of 2019 the new pneumonia epidemic began to spread of affecting the people, as individuals, our power is to try to be at home, go out less.

See some friends called to help students design their own avatar to wear a mask, as a technical person, I thought there must be more people there is such a demand, it is better to develop a simple program to achieve this demand can be considered to help reduce design sister workload.

So it took some time to write a feature called face-mask[1]command-line tools, can easily wear a mask to the picture in the portrait, but the direction and size of the masks are adapted to face oh ~

use

⚠️ ensure Python version 3.6 and above

Install face-mask
pip install face-mask

Use face-mask, specify the image path directly to wear a mask as a picture in portrait, and will generate a new picture (there are additional -with-mask suffix):
face-mask /path/to/face/picture

By specifying the --show option, you can also use the default image viewer to open the newly generated images:
face-mask /path/to/face/picture --show

effect

Give a man to wear a mask

to wear a mask to more than one person

to wear a mask cartoon characters

achieve

Thinking

To achieve the above effect, how should we do? You might think:

  • The first is to identify the human nose (nose_bridge) and face contour (chin)
  • The face is determined by the left face contour point (chin_left_point), a bottom face point (chin_bottom_point) and face the right point (chin_right_point)
  • It is determined by end point of the nose and face masks size of the height of the center line
  • The masks an average of two parts
    • Adjusting the size of the left mask, the face width of the left point to the centerline distance
    • Adjusting the size of the right masks, face width from the right point to the centerline
  • About the new merger masks masks
  • Rotating the new mask, the angle of the rotation angle with respect to the center line of the y-axis
  • The new mask on the original place

About face recognition, you can use face_recognition[2]the library to identify.

Image processing, you can use Pillow[3]the library for processing.

Code

Once you have the idea, implementation is part relatively easy task. But the transformation computation library familiar and pictures may take some time.

详细的代码请阅读 face-mask[4]。这里仅说明下最核心的步骤。

人脸识别

import face_recognition

face_image_np = face_recognition.load_image_file('/path/to/face/picture')
face_landmarks = face_recognition.face_landmarks(face_image_np)

借助 face_recognition 库可以轻松的识别出人像,最终得到的 face_landmarks 是一个列表,里面的每个 face_landmark 都表示一个人像数据。

face_landmark 是一个字典,其中的键表示人像特征,值表示该特征的点的列表。比如:

  • 键 nose_bridge 表示鼻梁
  • 键 chin 表示脸颊
    我们需要根据每个 face_landmark,给对应的头像戴上口罩。

获得鼻子和脸颊的特征点

import numpy as np

nose_bridge = face_landmark['nose_bridge']
nose_point = nose_bridge[len(nose_bridge) * 1 // 4]
nose_v = np.array(nose_point)

chin = face_landmark['chin']
chin_len = len(chin)
chin_bottom_point = chin[chin_len // 2]
chin_bottom_v = np.array(chin_bottom_point)
chin_left_point = chin[chin_len // 8]
chin_right_point = chin[chin_len * 7 // 8]

通过上述代码,我们获得了:

  • 表示上鼻梁的一个点 nose_point
  • 表示脸左点 chin_left_point
  • 表示脸右点 chin_right_point
  • 表示脸底点 chin_bottom_point

拆分、缩放和合并口罩

from PIL import Image

_face_img = Image.fromarray(face_image_np)
_mask_img = Image.open('/path/to/mask/picture')

# split mask and resize
width = _mask_img.width
height = _mask_img.height
width_ratio = 1.2
new_height = int(np.linalg.norm(nose_v - chin_bottom_v))

# left
mask_left_img = _mask_img.crop((0, 0, width // 2, height))
mask_left_width = get_distance_from_point_to_line(chin_left_point, nose_point, chin_bottom_point)
mask_left_width = int(mask_left_width * width_ratio)
mask_left_img = mask_left_img.resize((mask_left_width, new_height))

# right
mask_right_img = _mask_img.crop((width // 2, 0, width, height))
mask_right_width = get_distance_from_point_to_line(chin_right_point, nose_point, chin_bottom_point)
mask_right_width = int(mask_right_width * width_ratio)
mask_right_img = mask_right_img.resize((mask_right_width, new_height))

# merge mask
size = (mask_left_img.width + mask_right_img.width, new_height)
mask_img = Image.new('RGBA', size)
mask_img.paste(mask_left_img, (0, 0), mask_left_img)
mask_img.paste(mask_right_img, (mask_left_img.width, 0), mask_right_img)

上述代码主要做了如下内容:

  • 将口罩左右平均分为两个部分
  • 调整左口罩大小,宽度为脸左点到中心线的距离 * 宽度系数 1.2
  • 调整右口罩大小,宽度为脸右点到中心线的距离 * 宽度系数 1.2
  • 合并左右口罩为新口罩
    get_distance_from_point_to_line 用来获取一个点到一条线的距离,具体实现可看源代码。
    width_ratio 是宽度系数,用来适当扩大口罩。原因我们是根据脸颊的宽度计算口罩的宽度,但口罩是待在耳朵上的,真实宽度应该要更宽。

旋转口罩、并放到原图适当位置

# rotate mask
angle = np.arctan2(chin_bottom_point[1] - nose_point[1], chin_bottom_point[0] - nose_point[0])
rotated_mask_img = mask_img.rotate(angle, expand=True)

# calculate mask location
center_x = (nose_point[0] + chin_bottom_point[0]) // 2
center_y = (nose_point[1] + chin_bottom_point[1]) // 2

offset = mask_img.width // 2 - mask_left_img.width
radian = angle * np.pi / 180
box_x = center_x + int(offset * np.cos(radian)) - rotated_mask_img.width // 2
box_y = center_y + int(offset * np.sin(radian)) - rotated_mask_img.height // 2

# add mask
_face_img.paste(mask_img, (box_x, box_y), mask_img)

上述代码主要做了如下内容:

  • 旋转新口罩,角度为中心线相对于 y 轴的旋转角
  • 计算口罩应该放置的坐标
  • 将新口罩放在原图的计算出的坐标下
  • 最后就是将新图片保存到本地路径,代码不再展示。

总结

我们借助 face_recognition 库可以轻松的识别出人像,然后根据脸颊的宽度和鼻梁位置计算出口罩的大小、方向和位置,并最终生成出戴上口罩的图片。整个过程并不复杂,但在坐标计算上要格外小心,如此,我们便打造了一个短小精悍的“自动戴上口罩”程序!

对人脸识别感兴趣的同学可以在百度ai的官网上在线体验下,点击跳转 https://ai.baidu.com/tech/face/compare

文章来源于Prodesire ,作者Prodesire http://suo.im/6kbW29

Guess you like

Origin www.cnblogs.com/xkbc/p/12364386.html