Mediapipe 人脸网格 ( 旧 )
这篇教学会使用 MediaPipe 的人脸网格模型 ( Face Mesh ) 侦测人脸,再透过 OpenCV 读取摄影镜头图像进行辨识并在人脸上标记网格,最后还会做出只有 3D 人脸网格在移动的影片。
MidoaPipe 在 2023 年进行了比较大的改版和更新,虽然旧版的程序“可能”还可以运行,但建议使用新版,参考:Mediapipe 人脸特征点侦测 Face Landmark Detection ( 2023 年版 )
快速导览:
因为程序使用 Jupyter 搭配 Tensorflow 进行开发,所以请先阅读“使用 Anaconda”和“使用 MediaPipe”,安装对应的软件包,如果不要使用 Juputer,也可参考“使用 Python 虚拟环境”,建立虚拟环境进行实作。
人脸网格是什么?
MediaPipe 的 Face Mesh 可以将人脸转换为几何网格模型,经由机器学习判断人脸的表面和深度,再透过 468 个脸部标记 ( 面部姿态变换矩阵、三角形面部网格...等 ) 画出 3D 的人脸网格,由于已经计算出立体空间的特性,这个方法常用于扩增实境 ( AR ) 相关的应用。
从 Mediapipe 官方介绍中可以知道,经过深度运算后的网格,可以更准确得标记出嘴唇、眼睛、鼻子...等立体的五官 ( 图片来源 )。
使用 MediaPipe,绘制人脸网格
下方的程序码延伸“读取并播放影片”文章的范例,搭配 mediapipe 人脸网格的方法,透过摄影镜头获取图像后,即时标记出人脸网格。
import cv2
import mediapipe as mp
mp_drawing = mp.solutions.drawing_utils # mediapipe 繪圖方法
mp_drawing_styles = mp.solutions.drawing_styles # mediapipe 繪圖樣式
mp_face_mesh = mp.solutions.face_mesh # mediapipe 人臉網格方法
drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1) # 繪圖參數設定
cap = cv2.VideoCapture(0)
# 啟用人臉網格偵測,設定相關參數
with mp_face_mesh.FaceMesh(
max_num_faces=1, # 一次偵測最多幾個人臉
refine_landmarks=True,
min_detection_confidence=0.5,
min_tracking_confidence=0.5) as face_mesh:
if not cap.isOpened():
print("Cannot open camera")
exit()
while True:
ret, img = cap.read()
if not ret:
print("Cannot receive frame")
break
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 顏色 BGR 轉換為 RGB
results = face_mesh.process(img2) # 取得人臉網格資訊
if results.multi_face_landmarks:
for face_landmarks in results.multi_face_landmarks:
# 繪製網格
mp_drawing.draw_landmarks(
image=img,
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=img,
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=img,
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())
cv2.imshow('oxxostudio', img)
if cv2.waitKey(5) == ord('q'):
break # 按下 q 鍵停止
cap.release()
cv2.destroyAllWindows()
绘制只有网格的人脸
如果将原本摄影的画面隐藏,就可以将产生的 3D 人脸网格套用在其他图片里,形成有趣的图像
import cv2
import mediapipe as mp
import numpy as np # 載入 numpy 函式庫
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)
cap = cv2.VideoCapture(0)
with mp_face_mesh.FaceMesh(
max_num_faces=1,
refine_landmarks=True,
min_detection_confidence=0.5,
min_tracking_confidence=0.5) as face_mesh:
if not cap.isOpened():
print("Cannot open camera")
exit()
while True:
ret, img = cap.read()
if not ret:
print("Cannot receive frame")
break
img = cv2.resize(img,(480,320)) # 調整影像尺寸為 480x320
output = np.zeros((320,480,3), dtype='uint8') # 繪製 480x320 的黑色畫布
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
results = face_mesh.process(img2)
if results.multi_face_landmarks:
for face_landmarks in results.multi_face_landmarks:
# 繪製網格
mp_drawing.draw_landmarks(
image=output, # 繪製到 output
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=output, # 繪製到 output
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=output, # 繪製到 output
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())
cv2.imshow('oxxostudio', output) # 顯示 output
if cv2.waitKey(5) == ord('q'):
break # 按下 q 鍵停止
cap.release()
cv2.destroyAllWindows()
微信扫码关注
抖音扫码关注