Fork me on Gitee

opencv图像融合(给人脸添加一个眼镜)

基于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 the
15     # center
16     (h, w) = image.shape[:2]
17     (cX, cY) = (w // 2, h // 2)
18 
19     # grab the rotation matrix (applying the negative of the
20     # angle to rotate clockwise), then grab the sine and cosine
21     # (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 image
27     nW = int((h * sin) + (w * cos))
28     nH = int((h * cos) + (w * sin))
29 
30     # adjust the rotation matrix to take into account translation
31     M[0, 2] += (nW / 2) - cX
32     M[1, 2] += (nH / 2) - cY
33 
34     # perform the actual rotation and return the image
35     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             break
51         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~17
56             # 眉毛:18~22, 23~27
57             # 鼻梁:28~31
58             # 鼻子:31~36
59             # 眼睛:37~42, 43~48
60             # 嘴唇:49~68
61             # 左眼角和右眼角的位置
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/sx
76             # 求正切角,弧度转为度
77             degree = math.degrees(math.atan(r))
78             # 调用旋转方法
79             src = rotate_bound(src, degree)
80 
81             # mask处理,去掉旋转后的无关区域,初始化一个全0mask,用或运算处理mask
82             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             break
90     cap.release()
91     cv.destroyAllWindows()
92 
93 
94 if __name__ == '__main__':
95     video = 'video/face.mp4'
96     detect_face(video)

眼镜图片

 

效果

泊松融合三种参数效果在这里一样

除了眼镜图片较浅其他的还算可以吧

还可以扩展面部其他装饰

 

参考:

泊松融合:https://www.smwenku.com/a/5b7aec012b7177392c97200d

图像旋转:https://blog.csdn.net/hui3909/article/details/78854387

 

posted @ 2019-02-09 11:03  MARK+  阅读(2964)  评论(3编辑  收藏  举报