diff --git a/projects/detect_align_faces/README.md b/projects/detect_align_faces/README.md new file mode 100644 index 000000000..7eb08fd48 --- /dev/null +++ b/projects/detect_align_faces/README.md @@ -0,0 +1,25 @@ +# Detect and align faces + +This algorithm can detect the faces from picture and then align them. + +## Requirement + +**Dowload model parameters:** + +You should dowload the [model parameters](http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2) +from dlib, decompress and move to `./dat` + +**Installation:** + +```shell +$ pip install -r requirements.txt +``` + +## Usage + +```shell +$ python3 main.py [pic1, pic2...] +``` + +After the script finished, you will get some faces picture in the same +directory. diff --git a/projects/detect_align_faces/example.jpg b/projects/detect_align_faces/example.jpg new file mode 100644 index 000000000..28641d8d6 Binary files /dev/null and b/projects/detect_align_faces/example.jpg differ diff --git a/projects/detect_align_faces/main.py b/projects/detect_align_faces/main.py new file mode 100644 index 000000000..7c31988e0 --- /dev/null +++ b/projects/detect_align_faces/main.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +# +# Copyright(C) 2021 wuyaoping +# + + +import numpy as np +import os.path as osp +import sys +import cv2 +import dlib + +OUT_SIZE = (224, 224) +LEFT_EYE_RANGE = (36, 42) +RIGHT_EYE_RABGE = (42, 48) +LEFT_EYE_POS = (0.35, 0.3815) +DAT_PATH = "./dat/shape_predictor_68_face_landmarks.dat" + + +def main(files): + detector = dlib.get_frontal_face_detector() + sp = dlib.shape_predictor(DAT_PATH) + + for file in files: + img = cv2.imread(file, cv2.IMREAD_ANYCOLOR) + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + + faces = detect_align_faces(detector, sp, img) + for (idx, face) in enumerate(faces): + face = cv2.cvtColor(face, cv2.COLOR_RGB2BGR) + filename, ext = osp.splitext(file) + filename += '_face_{:03}'.format(idx) + ext + cv2.imwrite(filename, face) + + +def detect_align_faces(detector, sp, img): + faces = detector(img, 1) + res = [] + for face in faces: + shape = sp(img, face) + left, right = shape_to_pos(shape) + left_center = np.mean(left, axis=0) + right_center = np.mean(right, axis=0) + + dx = right_center[0] - left_center[0] + dy = right_center[1] - left_center[1] + angle = np.degrees(np.arctan2(dy, dx)) + dist = np.sqrt(dy ** 2 + dx ** 2) + out_dist = OUT_SIZE[0] * (1 - 2 * LEFT_EYE_POS[0]) + scale = out_dist / dist + center = ((left_center + right_center) // 2).tolist() + + mat = cv2.getRotationMatrix2D(center, angle, scale) + mat[0, 2] += (0.5 * OUT_SIZE[0] - center[0]) + mat[1, 2] += (LEFT_EYE_POS[1] * OUT_SIZE[1] - center[1]) + res_face = cv2.warpAffine(img, mat, OUT_SIZE, flags=cv2.INTER_CUBIC) + res.append(res_face) + + return res + + +def shape_to_pos(shape): + parts = [] + for p in shape.parts(): + parts.append((p.x, p.y)) + + left = parts[LEFT_EYE_RANGE[0]: LEFT_EYE_RANGE[-1]] + right = parts[RIGHT_EYE_RABGE[0]: RIGHT_EYE_RABGE[-1]] + + return (np.array(left), np.array(right)) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/projects/detect_align_faces/requirements.txt b/projects/detect_align_faces/requirements.txt new file mode 100644 index 000000000..97a266ea5 --- /dev/null +++ b/projects/detect_align_faces/requirements.txt @@ -0,0 +1,3 @@ +dlib==19.22.1 +numpy==1.21.2 +opencv-python==4.5.3.56