Put a mask on your goddess with Python ~

Time:2020-9-22

preface

The new pneumonia epidemic, which starts to spread at the end of 2019, affects people’s hearts. As individuals, what we can do is to stay at home as much as possible and go out less.

Seeing that some friends asked design classmates to help them put on masks for their head portraits, as technicians, I thought that there must be more people who have such demands. It is better to develop a simple program to realize this demand, which can also be regarded as helping design sister reduce the workload.

So I spent some time writing a command-line tool called face mask [1], which can easily put on masks for people in pictures, and the direction and size of masks are adapted to face~

use

installface-mask

Make sure Python version is 3.6 and above

pip install face-mask

useface-mask

Directly specify the image path to put on the mask for the portrait in the picture, and a new image will be generated (additional-with-maskSuffix:

face-mask /path/to/face/picture

By specifying--showYou can also use the default picture viewer to open a newly generated picture:

face-mask /path/to/face/picture --show

effect

Put a mask on a person

Mask multiple people

Put masks on cartoon characters

realization

thinking

What should we do to achieve the above effect? Think of it this way:

  • The first is to recognize the nose_ Bridge and chin

  • The left point of the face (Chin) is determined by the contour of the face_ left_ Point, Chin_ bottom_ Point and chin_ right_ point)

  • The height and center line of mask size are determined by nose and face bottom point

  • Divide the mask into two parts

    • Adjust the size of the left mask to the distance from the left point of the face to the center line

    • Adjust the size of the right mask to the distance from the right point of the face to the center line

    • Merge left and right masks into new masks

  • Rotate the new mask at the angle of the center line relative to the Y axis

  • Put the new mask in the proper position in the original picture

aboutFace recognitionYou can use face_ Recognition [2] library.

aboutimage processing, which can be processed using the pillow [3] library.

code

With ideas, implementation is a relatively easy thing. However, it may take some time to get familiar with the library and transform the images.

For detailed code, please read face mask [4]. Only the core steps are described here.

Face recognition

import face_recognition

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

With the help offace_recognitionLibrary can easily identify the portrait, and finally get theface_landmarksIt’s a list, each of themface_landmarkIt means that a person is like data.

face_landmarkIs a dictionary where the key represents the portrait feature and the value represents the list of points for that feature. For example:

  • keynose_bridgeThe bridge of the nose

  • keychinIt means cheek

We need to base on eachface_landmarkPut a mask on the corresponding head portrait.

Get the feature points of nose and cheek

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]

Through the above code, we obtain:

  • A point representing the bridge of the upper nosenose_point

  • Left point of facechin_left_point

  • Right point of facechin_right_point

  • It means the bottom of the facechin_bottom_point

Split, zoom and merge masks

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)

The above code mainly includes the following contents:

  • Divide the mask into two parts

  • Adjust the size of the left mask. The width is the distance from the left point of the face to the center line * the width coefficient is 1.2

  • Adjust the size of the right mask. The width is the distance from the right point of the face to the center line * the width coefficient is 1.2

  • Merge left and right masks into new masks

get_distance_from_point_to_lineUsed to get a point to a line distance, the specific implementation can see the source code.

width_ratioIs the width factor, which is used to properly enlarge the mask. The reason is that we calculate the width of the mask according to the width of the cheek, but the mask stays on the ear, and the actual width should be wider.

Rotate the mask and place it in the proper position of the original picture

# 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)

The above code mainly includes the following contents:

  • Rotate the new mask at the angle of the center line relative to the Y axis

  • Calculate the coordinates where the mask should be placed

  • Put the new mask under the calculated coordinates of the original figure

Finally, the new image will be saved to the local path, and the code will not be displayed.

summary

We useface_recognitionThe library can easily identify the portrait, and then calculate the size, direction and position of the exit mask according to the width of the cheek and the position of the bridge of the nose, and finally generate the picture of wearing the mask. The whole process is not complicated, but we should be very careful in coordinate calculation. In this way, we have created a short and concise “automatic mask on” program!

Recommended Today

13 Linux utility recommended, all are artifact!

This paper introduces several useful Linux tools, hoping to help. 1. View process bandwidth usage – nethogs Nethogs is a network traffic monitoring tool under the terminal, which can intuitively display the bandwidth occupied by each process. Download:http://sourceforge.net/projec… [[email protected] ~]#yum-y install libpcap-develncurses-devel [[email protected] ~]# tar zxvf nethogs-0.8.0.tar.gz [[email protected] ~]# cd nethogs [[email protected] nethogs]# make && make install [[email protected] nethogs]# nethogs eth0 2. Hard disk read performance test iozone Iozone is a Linux file […]