网络说明
该网络由两个协同工作的实时深度神经网络模型组成:一个在完整图像上运行并计算人脸位置的检测器,以及一个在这些位置上运行并预测近似 3D 表面的 3D 人脸界标模型 通过回归。 准确的人脸裁剪大大减少了对常见数据增强的需求,例如由旋转、平移和尺度变化组成的仿射变换。
3D 网络接收裁剪后的视频帧作为输入,无需额外的深度输入。 模型输出 3D 点的位置和人脸出现的置信度,并在输入中合理对齐。 一种常见的替代方法是为每个地标预测一个 2D 图,但它不适合深度预测,并且对于这么多点的计算成本很高。 这里采用通过迭代引导和改进预测,进一步提高了模型的准确性和鲁棒性。
人脸变换模块
Face Landmark Model在屏幕坐标空间中进行单相机人脸地标检测:X坐标和Y坐标是归一化的屏幕坐标,而Z坐标是相对的,在弱透视投影相机模型下缩放为X坐标. 这种格式非常适合某些应用程序,但它不能直接启用所有增强现实 (AR) 功能,例如将虚拟 3D 对象与检测到的人脸对齐。
公制 3D 空间:Face Transform 模块中建立的度量 3D 空间是右手正交正交度量 3D 坐标空间。在空间内,有一个虚拟透视相机位于空间原点,指向Z轴负方向。在当前的管道中,假设输入的相机帧正是由这个虚拟相机观察到的,因此它的参数稍后用于将屏幕地标坐标转换回 Metric 3D 空间。虚拟相机参数可以自由设置,但为了获得更好的效果,建议将它们设置为尽可能接近真实的物理相机参数。
Demo实现
命令行执行:
pip install mediapipe 复制代码
代码基本步骤逻辑:
1. 输入图像;
2. 人脸界标屏幕坐标转换为 Metric 3D 空间坐标;
3. 人脸姿态变换矩阵被估计为从规范人脸度量标志集到运行时人脸度量标志集的刚性线性映射,以最小化两者之间的差异;
4. 使用运行时面部度量地标作为顶点位置 (XYZ) 创建面部网格,而顶点纹理坐标 (UV) 和三角形拓扑均继承自规范面部模型。
读取单张图像进行绘制人脸网络:静态图像模式:
如果设置为false
,则解决方案将输入图像视为视频流。它将尝试检测第一张输入图像中的人脸,并在成功检测后进一步定位人脸标志。在随后的图像中,一旦检测到所有[max_num_faces]人脸并定位了相应的人脸界标,它就会简单地跟踪这些界标而不调用另一个检测,直到它失去对任何人脸的跟踪。这减少了延迟,是处理视频帧的理想选择。如果设置为true
,人脸检测会在每个输入图像上运行,非常适合处理一批可能不相关的静态图像。默认为false
。MAX_NUM_FACES要检测的最大人脸数。默认为1
细化地标:
是否进一步细化眼睛和嘴唇周围的界标坐标,并通过应用[Attention Mesh Model]输出额外的虹膜周围的界标。默认为false
。
MIN_DETECTION_CONFIDENCE[0.0, 1.0]
人脸检测模型中的最小置信度值 被认为是成功的检测。默认为0.5。
MIN_TRACKING_CONFIDENCE[0.0, 1.0]
来自地标跟踪模型的最小置信度值(将其设置为更高的值可以提高解决方案的稳健性,但代价是更高的延迟。如果[static_image_mode]为 则忽略true
,其中人脸检测仅在每个图像上运行。默认为0.5
。
多面地标:
检测/跟踪的人脸集合,其中每个人脸表示为 468 个人脸标志的列表,每个标志由x
和y
组成z
。x
并分别由图像宽度和高度y
归一化。表示以头部中心深度为原点的地标深度,值越小,地标距离相机越近。
import uuid import cv2 import mediapipe as mp mp_drawing = mp.solutions.drawing_utils mp_drawing_styles = mp.solutions.drawing_styles mp_face_mesh = mp.solutions.face_mesh drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1) with mp_face_mesh.FaceMesh( static_image_mode=True, max_num_faces=1, refine_landmarks=True, min_detection_confidence=0.5) as face_mesh: image = cv2.imread('2.jpg') # Convert the BGR image to RGB before processing. results = face_mesh.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) # Print and draw face mesh landmarks on the image. annotated_image = image.copy() for face_landmarks in results.multi_face_landmarks: print('face_landmarks:', face_landmarks) mp_drawing.draw_landmarks( image=annotated_image, landmark_list=face_landmarks, connections=mp_face_mesh.FACEMESH_TESSELATION, landmark_drawing_spec=None, connection_drawing_spec=mp_drawing_styles .get_default_face_mesh_tesselation_style()) mp_drawing.draw_landmarks( image=annotated_image, landmark_list=face_landmarks, connections=mp_face_mesh.FACEMESH_CONTOURS, landmark_drawing_spec=None, connection_drawing_spec=mp_drawing_styles .get_default_face_mesh_contours_style()) mp_drawing.draw_landmarks( image=annotated_image, landmark_list=face_landmarks, connections=mp_face_mesh.FACEMESH_IRISES, landmark_drawing_spec=None, connection_drawing_spec=mp_drawing_styles .get_default_face_mesh_iris_connections_style()) name = uuid.uuid1() cv2.imwrite('./' + str(name) + '.png', annotated_image) 复制代码
示例图像: