MediaPipe의 Python 래퍼를 사용하여 실시간으로 얼굴 특징점을 얻습니다.

소개



이 기사는 얼굴학 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() # インスタンスを終了させる

실행하면 이런 식으로 얼굴 위에 얼굴 특징점을 그릴 수 있다


웹캠으로 실시간으로 얼굴 특징점을 그리기



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상에서 데모를 시험할 수 있습니다. 이쪽도 간편하게 시험할 수 있으므로 꼭 해 보세요.


참고


  • MediaPipe FaceMesh
  • Real-time Facial Surface Geometry from Monocular Video on Mobile GPUs
  • 좋은 웹페이지 즐겨찾기