|
- import cv2
- import dlib
- import numpy as np
- from imutils import face_utils
- """
- 思绪:
- 第一步:2D人脸关頭點檢测;第二步:3D人脸模子匹配;
- 第三步:求解3D點和對應2D點的轉换瓜葛;第四步:按照扭轉矩阵求解欧拉角。
- """
- # 加载人脸檢测和姿式估量模子(dlib)
- face_landmark_path = 'D:/myworkspace/JupyterNotebook/fatigue_detecting/model/shape_predictor_68_face_landmarks.dat'
- """
- 只要晓得世界坐標系内點的位置、像素坐標位置和相機参数便可以搞定扭轉和平移矩阵(OpenCV自带函数solvePnp())
- """
- # 世界坐標系(UVW):填写3D参考點,该模子参考
- object_pts = np.float32([[6.825897, 6.760612, 4.402142], #33左眉左上角
- [1.330353, 7.122144, 6.903745], #29左眉右角
- [-1.330353, 7.122144, 6.903745], #34右眉左角
- [-6.825897, 6.760612, 4.402142], #38右眉右上角
- [5.311432, 5.485328, 3.987654], #13左眼左上角
- [1.789930, 5.393625, 4.413414], #17左眼右上角
- [-1.789930, 5.393625, 4.413414], #25右眼左上角
- [-5.311432, 5.485328, 3.987654], #21右眼右上角
- [2.005628瘦臉,, 1.409845, 6.165652], #55鼻子左上角
- [-2.005628, 1.409845, 6.165652], #49鼻子右上角
- [2.774015, -2.080775, 5.048531], #43嘴左上角
- [-2.774015, -2.080775, 5.048531],#39嘴右上角
- [0.000000, -3.116408, 6.097667], #45嘴中心下角
- [0.000000, -7.415691, 4.070434]])#6下巴角
- # 相機坐標系(XYZ):添加相機内参
- K = [6.5308391993466671e+002, 0.0, 3.1950000000000000e+002,
- 0.0, 6.5308391993466671e+002, 2.3950000000000000e+002,
- 0.0, 0.0, 1.0]# 等價于矩阵[fx, 0, cx; 0, fy, cy; 0, 0, 1]
- # 图象中間坐標系(uv):相機畸變参数[k1, k2, p1, p2, k3]
- D = [7.0834633684407095e-002, 6.9140193737175351e-002, 0.0, 0.0, -1.3073460323689292e+000]
- # 像素坐標系(xy):填写凸轮的本征和畸變系数
- cam_matrix = np.array(K).reshape(3, 3).astype(np.float32)
- dist_coeffs = np.array(D).reshape(5, 1).astype(np.float32)
- # 從新投影3D點的世界坐標轴以驗證成果姿式
- reprojectsrc = np.float32([[10.0, 10.0, 10.0],
- [10.0, 10.0, -10.0],
- [10.0, -10.0, -10.0],
- [10.0, -10.0, 10.0],
- [-10.0, 10.0, 10.0],
- [-10.0, 10.0, -10.0],
- [-10.0, -10.0, -10.0],
- [-10.0, -10.0, 10.0]])
- # 绘制正方體12轴
- line_pairs = [[0, 1], [1, 2], [2, 3], [3, 0],
- [4, 5], [5, 6], [6, 7], [7, 4],
- [0, 4], [1, 5], [2, 6], [3, 7]]
- def get_head_pose(shape):
- # 填写2D参考點,注释遵守
- """
- 17左眉左上角/21左眉右角/22右眉左上角/26右眉右上角/36左眼左上角/39左眼右上角/42右眼左上角/
- 4減肥茶,5右眼右上角/31鼻子左上角/35鼻子右上角/48左上角/54嘴右上角/57嘴中心下角/8下巴角
- """
- # 像素坐標调集
- image_pts = np.float32([shape[17], shape[21], shape[22], shape[26], shape[36],
- shape[39], shape[42], shape[45], shape[31], shape[35],
- shape[48], shape[54], shape[57], shape[8]])
- """
- 用solvepnp或sovlepnpRansac,输入3d點、2d點、相機内参、相機畸變,输出r、t以後
- 用projectPoints,输入3d點、相機内参、相機畸變、r、t,输出重投影2d點
- 计较原2d點和重投影2d點的間隔作為重投影偏差
- """
- # solvePnP计较姿式——求解扭轉和平移矩阵:
- # rotation_vec暗示扭轉矩阵,translation_vec暗示平移矩阵,cam_matrix與K矩阵對應,dist_coeffs與D矩阵對應。
- _, rotation_vec, translation_vec = cv2.solvePnP(object_pts, image_pts, cam_matrix, dist_coeffs)
- # projectPoints從新投影偏差
- reprojectdst, _ = cv2.projectPoints(reprojectsrc, rotation_vec, translation_vec, cam_matrix,dist_coeffs)
- reprojectdst = tuple(map(tuple, reprojectdst.reshape(8, 2)))# 以8行2列显示
- # 计较欧拉角calc euler angle
- # 参考
- rotation_mat, _ = cv2.Rodrigues(rotation_vec)#罗德里格斯公式(将扭轉矩阵轉换為扭轉向量)
- pose_mat = cv2.hconcat((rotation_mat, translation_vec))# 程度拼接,vconcat垂直拼接
- # eulerAngles –可選的三元素矢量,包括三個以度為单元的欧拉扭轉角度
- _, _, _, _, _, _, euler_angle = cv2.decomposeProjectionMatrix(pose_mat)# 将投影矩阵分化為扭轉矩阵和相機矩阵
- return reprojectdst, euler_angle
- def main():
- # return
- cap = cv2.VideoCapture(0)
- if not cap.isOpened():
- print("Unable to connect to came山楂茶,ra.")
- return
- # 檢测人脸
- detector = dlib.get_frontal_face_detector()
- # 檢测第一小我脸的关頭點
- predictor = dlib.shape_predictor(face_landmark_path)
- while cap.isOpened()腰酸背痛止痛,:
- ret, frame = cap.read()
- if ret:
- face_rects = detector(frame, 0)
- if len(face_rects) > 0:
- # 轮回面部位置信息,利用predictor(gray, rect)得到面部特性位置的信息
- shape = predictor(frame, face_rects[0])
- # 将面部特性信息轉换為数组array的格局
- 瘦肚子方法, shape = face_utils.shape_to_np(shape)
- # 获得頭部姿态
- reprojectdst, euler_ang日貨百貨推薦,le = get_head_pose(shape)
- pitch = format(euler_angle[0, 0])
- yaw = format(euler_angle[1, 0])
- roll = format(euler_angle[2, 0])
- print('pitch:{}, yaw:{}, roll:{}'.format(pitch, yaw, roll))
- # 標出68個特性點
- for (x, y) in shape:
- cv2.circle(frame, (x, y), 1, (0, 0, 255), -1)
- # 绘制正方體12轴
- for start, end in line_pairs:
- cv2.line(frame, reprojectdst[start], reprojectdst[end], (0, 0, 255))
- # 显示角度成果
- cv2.putText(frame, "X: " + "{:7.2f}".format(euler_angle[0, 0]), (20, 20), cv2.FONT_HERSHEY_SIMPLEX,0.75, (0, 0, 255), thickness=2)
- cv2.putText(frame, "Y: " + "{:7.2f}".format(euler_angle[1, 0]), (20, 50), cv2.FONT_HERSHEY_SIMPLEX,0.75, (0, 0, 255), thickness=2)
- cv2.putText(frame, "Z: " + "{:7.2f}".format(euler_angle[2, 0]), (20, 80), cv2.FONT_HERSHEY_SIMPLEX,0.75, (0, 0, 255), thickness=2)
- # 按q退出提醒
- cv2.putText(frame, "Press 'q': Quit", (20, 450),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (84, 255, 159), 2)
- # 窗口显示 show with opencv
- cv2.imshow("Head_Posture", frame)
- if cv2.waitKey(1) & 0xFF == ord('q'):
- break
- # 開释摄像頭 release camera
- cap.release()
- # do a bit of cleanup
- cv2.destroyAllWindows()
- if __name__ == '__main__':
- main()
複製代碼 |
|