14
2

More than 3 years have passed since last update.

MediaPipeのPythonラッパーを使ってリアルタイムに顔特徴点を取得する

Last updated at Posted at 2020-12-10

はじめに

この記事は顔学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

スクリーンショット 2020-12-10 17.24.33.png

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() # インスタンスを終了させる

実行するとこんな感じで顔の上に顔特徴点を描画できる
スクリーンショット 2020-12-10 17.30.07.pngスクリーンショット 2020-12-10 17.31.03.pngスクリーンショット 2020-12-10 17.30.53.png

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上でデモが試せます.こちらも手軽に試せるので是非やってみてください.

スクリーンショット 2020-12-10 18.33.06.png
スクリーンショット 2020-12-10 18.33.01.png

参考

14
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
2