基于dlib68点人脸检测的小功能实现
图像旋转找的现成的方法,稍稍麻烦点的地方就是mask处理,虽然目的达到了,但是效果一般
1 import numpy as np 2 import cv2 as cv 3 import dlib 4 import math 5 6 # 做一个戴眼镜的滤镜效果 7 8 detector = dlib.get_frontal_face_detector() 9 predictor = dlib.shape_predictor('dlib/shape_predictor_68_face_landmarks.dat')10 11 12 # 图像旋转,保持原来大小13 def rotate_bound(image, angle):14 # grab the dimensions of the image and then determine the15 # center16 (h, w) = image.shape[:2]17 (cX, cY) = (w // 2, h // 2)18 19 # grab the rotation matrix (applying the negative of the20 # angle to rotate clockwise), then grab the sine and cosine21 # (i.e., the rotation components of the matrix)22 M = cv.getRotationMatrix2D((cX, cY), -angle, 1.0)23 cos = np.abs(M[0, 0])24 sin = np.abs(M[0, 1])25 26 # compute the new bounding dimensions of the image27 nW = int((h * sin) + (w * cos))28 nH = int((h * cos) + (w * sin))29 30 # adjust the rotation matrix to take into account translation31 M[0, 2] += (nW / 2) - cX32 M[1, 2] += (nH / 2) - cY33 34 # perform the actual rotation and return the image35 return cv.warpAffine(image, M, (nW, nH))36 37 38 def detect_face(camera_idx):39 # camera_idx: 电脑自带摄像头或者usb摄像头40 cv.namedWindow('detect')41 cap = cv.VideoCapture(camera_idx)42 43 while cap.isOpened():44 cv.namedWindow('detect', cv.WINDOW_AUTOSIZE)45 ok, frame = cap.read()46 # 为摄像头的时候,翻转画面47 if camera_idx == 0 or camera_idx == 1:48 frame = cv.flip(frame, 1, dst=None)49 if not ok:50 break51 gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)52 rects = detector(gray, 0)53 for i in range(len(rects)):54 landmarks = np.matrix([[p.x, p.y] for p in predictor(frame, rects[i]).parts()])55 # 脸轮廓:1~1756 # 眉毛:18~22, 23~2757 # 鼻梁:28~3158 # 鼻子:31~3659 # 眼睛:37~42, 43~4860 # 嘴唇:49~6861 # 左眼角和右眼角的位置62 pos_left = (landmarks[0][0, 0], landmarks[36][0, 1])63 pos_right = (landmarks[16][0, 0], landmarks[45][0, 1])64 face_center = (landmarks[27][0, 0], landmarks[27][0, 1])65 src = cv.imread('images/glasses.jpg')66 # 433x187眼镜图片原始大小,按人脸比例缩放一下67 length = pos_right[0] - pos_left[0]68 width = int(187/(433/length))69 src = cv.resize(src, (length, width), interpolation=cv.INTER_CUBIC)70 71 # 角度旋转,通过计算两个眼角和水平方向的夹角来旋转眼镜72 sx = landmarks[36][0, 0] - landmarks[45][0, 0]73 sy = landmarks[36][0, 1] - landmarks[45][0, 1]74 # 夹角正切值75 r = sy/sx76 # 求正切角,弧度转为度77 degree = math.degrees(math.atan(r))78 # 调用旋转方法79 src = rotate_bound(src, degree)80 81 # mask处理,去掉旋转后的无关区域,初始化一个全0mask,用或运算处理mask82 src_mask = np.zeros(src.shape, src.dtype)83 src_mask = cv.bitwise_or(src, src_mask)84 # 泊松融合85 output = cv.seamlessClone(src, frame, src_mask, face_center, cv.MIXED_CLONE)86 cv.imshow('detect', output)87 c = cv.waitKey(10)88 if c & 0xFF == ord('q'):89 break90 cap.release()91 cv.destroyAllWindows()92 93 94 if __name__ == '__main__':95 video = 'video/face.mp4'96 detect_face(video)
眼镜图片
效果
泊松融合三种参数效果在这里一样
除了眼镜图片较浅其他的还算可以吧
还可以扩展面部其他装饰
参考:
泊松融合:
图像旋转: