はじめに
この記事は顔学2020アドベントカレンダーの17日目の記事です.
今日は顔特徴点(Face Landmark)取得に利用できるMediaPipeのPythonラッパーが出ていたので,Webカメラで動作させてみたいと思います.
MediaPipe FaceMeshのコードを参考にしています.
インストール
> pip install mediapipe
顔特徴点の取得
取得した顔特徴点は3次元空間上の座標として渡されます.その特徴点をもとに(三角)ポリゴンメッシュを作成しています.RGBDカメラなどによる奥行き情報(Depth)がなくても,Webカメラの2次元画像から顔特徴点モデル(face landmark model)を作成することができます.
Real-time Facial Surface Geometry from Monocular Video on Mobile GPUs
import mediapipe as mp
import cv2 as cv
mp_drawing = mp.solutions.drawing_utils # 描画用のインスタンス
mp_face_mesh = mp.solutions.face_mesh # MLソリューションの顔メッシュインスタンス
face_mesh = mp_face_mesh.FaceMesh(
static_image_mode=True,
max_num_faces=1,
min_detection_confidence=0.5)
drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1)
image = cv.imread(PATH_TO_IMG) # 画像の読み込み
rgb_image = cv.cvtColor(image, cv.COLOR_BGR2RGB) # RGB形式に変換
results = face_mesh.process(rgb_image) # 顔メッシュを計算
annotated_image = image.copy() # 描画用の画像をコピーしておく
for face_landmarks in results.multi_face_landmarks: # 画像内の全ての顔の顔特徴点
print(face_landmarks)
###################################
# landmark {
# x: 0.4557078182697296
# y: 0.6814221143722534
# z: -0.022573839873075485
# }
# ...
# landmark {
# x: 0.5611855983734131
# y: 0.48328155279159546
# z: 0.0023858787026256323
# }
###################################
mp_drawing.draw_landmarks(
image=annotated_image,
landmark_list=face_landmarks,
connections=mp_face_mesh.FACE_CONNECTIONS,
landmark_drawing_spec=drawing_spec,
connection_drawing_spec=drawing_spec) # 特徴点の描画
cv.imwrite('face_mesh_result.png', annotated_image) # 保存
face_mesh.close() # インスタンスを終了させる
Webカメラでリアルタイムに顔特徴点を描画
MediaPipe FaceMeshのサンプルコードにfpsの計算・動画保存・スクリーンショット機能を追加したものです.
import mediapipe as mp
import cv2 as cv
mp_drawing = mp.solutions.drawing_utils # 描画用のインスタンス
mp_face_mesh = mp.solutions.face_mesh # MLソリューションの顔メッシュインスタンス
face_mesh = mp_face_mesh.FaceMesh(
min_detection_confidence=0.5, min_tracking_confidence=0.5)
drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1)
cap = cv.VideoCapture(0)
w = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
h = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
fourcc = cv.VideoWriter_fourcc('m', 'p', '4', 'v')
video = cv.VideoWriter('face_mesh_video.mp4', fourcc, 30, (w, h))
while cap.isOpened():
tick = cv.getTickCount()
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 = cv.cvtColor(cv.flip(image, 1), cv.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)
print(results.multi_face_landmarks[0])
# Draw the face mesh annotations on the image.
image.flags.writeable = True
image = cv.cvtColor(image, cv.COLOR_RGB2BGR)
if results.multi_face_landmarks:
for face_landmarks in results.multi_face_landmarks:
print(face_landmarks)
mp_drawing.draw_landmarks(
image=image,
landmark_list=face_landmarks,
connections=mp_face_mesh.FACE_CONNECTIONS,
landmark_drawing_spec=drawing_spec,
connection_drawing_spec=drawing_spec)
fps = cv.getTickFrequency() / (cv.getTickCount() - tick) # fpsの計算
cv.putText(
image,
"FPS: " + str(int(fps)),
(image.shape[1] - 150, 40),
cv.FONT_HERSHEY_PLAIN,
2,
(0, 255, 0),
2,
cv.LINE_AA)
cv.imshow('MediaPipe FaceMesh', image)
video.write(image)
if cv.waitKey(5) & 0xFF == 27: # escで終了
break
if cv.waitKey(5) & 0xFF == 32: # spaceでスクリーンショット
dt = datetime.datetime.now()
cv.imwrite(dt.isoformat() + ".png", image)
face_mesh.close()
cap.release()
動作環境はMacBookPro2017と標準搭載のカメラです.おおむねリアルタイム(fps30以上)で処理できていそうです.GPUで処理させたらもっとはやくなると思います.
さいごに
今日は顔特徴点を取得する方法と,それをもとに特徴点を描画する方法を紹介しました.以前紹介したOpenFaceでも同じようなことができるのですが,MediaPipeのほうが新しい技術なのでその分動作が高速だったり精度がよかったりしそうですね.この辺は今後比較できたらと思っています.
MediaPipeにはこれ以外にも手指の認識や姿勢推定のモデルも対応していて,Web上でデモが試せます.こちらも手軽に試せるので是非やってみてください.