1.摘要
MediaPipe Selfie Segmentation对场景中突出的人进行了分割。它可以在智能手机和笔记本电脑上实时运行。预期的使用场景包括自拍效果和视频会议,即人们离相机很近(小于2米)。
2.模型
在这个解决方案中,我们提供了两种模型:一般模型和景观模型。两种模型都基于 MobileNetV3,并进行了修改以提高效率。通用模型在 256x256x3 (HWC) 张量上运行,并输出代表分割掩码的 256x256x1 张量。景观模型类似于通用模型,但在 144x256x3 (HWC) 张量上运行。它比一般模型具有更少的 FLOP,因此运行速度更快。请注意,在将输入图像输入 ML 模型之前,MediaPipe Selfie Segmentation 会自动将输入图像的大小调整为所需的张量维度。
通用模型也为 ML Kit 提供支持,景观模型的一个变体为 Google Meet 提供支持。
3.ML管道
管道被实现为一个 MediaPipe 图,它使用来自自拍分割模块的自拍分割子图。
4.解决方案 API
4.2配置选项
STATIC_IMAGE_MODE
:如果设置为 false,该解决方案会将输入图像视为视频流。它将尝试检测第一张输入图像中的人脸,并在成功检测后进一步定位人脸地标。在随后的图像中,一旦检测到所有 max_num_faces 人脸并定位了相应的人脸地标,它就会简单地跟踪这些地标,而不会调用另一个检测,直到它失去对任何人脸的跟踪。这减少了延迟,非常适合处理视频帧。如果设置为 true,人脸检测会在每个输入图像上运行,非常适合处理一批静态的、可能不相关的图像。默认为false。MAX_NUM_FACES
:要检测的最大人脸数。默认为 1。MIN_DETECTION_CONFIDENCE
:来自人脸检测模型的最小置信值 ([0.0, 1.0]),以便将检测视为成功。默认为 0.5。MIN_TRACKING_CONFIDENCE
:来自地标跟踪模型的最小置信值 ([0.0, 1.0]),用于将被视为成功跟踪的人脸地标,否则将在下一个输入图像上自动调用人脸检测。将其设置为更高的值可以提高解决方案的稳健性,但代价是更高的延迟。如果 static_image_mode 为true,则忽略,人脸检测在每个图像上运行。默认为 0.5。
4.3输出
MULTI_FACE_LANDMARKS
:被检测/跟踪的人脸的集合,其中每个人脸被表示为468个人脸地标的列表,每个地标由x、y和z组成。x和y分别由图像的宽度和高度归一化为[0.0,1.0]。Z为地标深度,头部中心深度为原点,值越小,地标距离相机越近。z的大小与x的大小大致相同。
5.Python解决方案API
支持配置选项:
- static_image_mode
- max_num_faces
- min_detection_confidence
- min_tracking_confidence
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
# For static images:
IMAGE_FILES = []
drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1)
with mp_face_mesh.FaceMesh(
static_image_mode=True,
max_num_faces=1,
min_detection_confidence=0.5) as face_mesh:
for idx, file in enumerate(IMAGE_FILES):
image = cv2.imread(file)
# 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.
if not results.multi_face_landmarks:
continue
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())
cv2.imwrite(annotated_image' + str(idx) + '.png', annotated_image)
# For webcam input:
drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1)
cap = cv2.VideoCapture(0)
with mp_face_mesh.FaceMesh(
min_detection_confidence=0.5,
min_tracking_confidence=0.5) as face_mesh:
while cap.isOpened():
success, image = cap.read()
if not success:
print("Ignoring empty camera frame.")
# If loading a video, use 'break' instead of 'continue'.
continue
# Flip the image horizontally for a later selfie-view display, and convert
# the BGR image to RGB.
image = cv2.cvtColor(cv2.flip(image, 1), cv2.COLOR_BGR2RGB)
# To improve performance, optionally mark the image as not writeable to
# pass by reference.
image.flags.writeable = False
results = face_mesh.process(image)
# Draw the face mesh annotations on the image.
image.flags.writeable = True
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
if results.multi_face_landmarks:
for face_landmarks in results.multi_face_landmarks:
mp_drawing.draw_landmarks(
image=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=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())
cv2.imshow('MediaPipe FaceMesh', image)
if cv2.waitKey(5) & 0xFF == 27:
break
cap.release()