見出し画像

MediaPipe 入門 (5) - Holistic

以下の記事を参考にして書いてます。

Holistic - mediapipe

前回

1. MediaPipe Holistic

MediaPipe Holistic」は、動画から人間の姿勢と顔と手のランドマークを推論するライブラリです。

2. モデル

◎ Landmark Models
「MediaPipe Holistic」は、「MediaPipe Pose」「MediaPipe Face Mesh」「MediaPipe Hands」の姿勢、顔、手のランドマークモデルをそれぞれ利用して、合計543のランドマーク(33個の姿勢のランドマーク、468個の顔のランドマーク、21個の手のランドマーク)を生成します。

◎ Hand Recrop Model
ポーズモデルの精度が低く、結果として得られる手のROIがまだ不正確である場合は、空間トランスフォーマーの役割を果たし、ハンドモデルの推論時間の約10%しかかからない、追加の軽量ハンドリクロップモデルを実行します。 

3. ソリューションAPI

◎ オプション

・STATIC_IMAGE_MODE
静止画かどうか。(true:静止画,false:動画, デフォルト:false)

・UPPER_BODY_ONLY
上半身のみかどうか(false:上半身のみ,true: 全身, デフォルト:false)

・SMOOTH_LANDMARKS
ジッターを減らすかどうか。静止画では無処理。 (デフォルト:true)

・MIN_DETECTION_CONFIDENCE
ランドマーク検出成功とみなす最小信頼値。([0.0、1.0], デフォルト:0.5)

・MIN_TRACKING_CONFIDENCE
ランドマーク追跡成功とみなす最小信頼値。([0.0、1.0], デフォルト:0.5)

◎ 出力

・POSE_LANDMARKS
姿勢のランドマークのリスト。

各ランドマークは、以下で構成されている。
- x : ランドマークのX座標([0.0、1.0])
- y : ランドマークのY座標([0.0、1.0])
- z : ランドマークの深度。腰の中点を原点として、値が小さいほどカメラに近くなる。全身モードでのみ予測される。([0.0、1.0])
- visibility : 画像表示(存在し遮られていない)の可能性([0.0、1.0])。

・FACE_LANDMARKS
468個の顔のランドマークのリスト。

各ランドマークは、以下で構成されている。
- x : ランドマークのX座標([0.0、1.0])
- y : ランドマークのY座標([0.0、1.0])
- z : ランドマークの深度。頭の中点を原点として、値が小さいほどカメラに近くなる。([0.0、1.0])

・LEFT_HAND_LANDMARKS
21個の左手のランドマークのリスト。

各ランドマークは、以下で構成されている。
- x : ランドマークのX座標([0.0、1.0])
- y : ランドマークのY座標([0.0、1.0])
- z : ランドマークの深度。手首の深度を原点として、値が小さいほどカメラに近くなる。([0.0、1.0])

・RIGHT_HAND_LANDMARKS
21個の右手のランドマークのリスト。

4. Python ソリューションAPI

◎ サポートオプション

・static_image_mode
・upper_body_only
・smooth_landmarks
・min_detection_confidence
・min_tracking_confidence

◎ コード

import cv2
import mediapipe as mp
mp_drawing = mp.solutions.drawing_utils
mp_holistic = mp.solutions.holistic

# 静止画像の場合:
with mp_holistic.Holistic(static_image_mode=True) as holistic:
  for idx, file in enumerate(file_list):
    image = cv2.imread(file)
    image_height, image_width, _ = image.shape
    # 処理する前にBGR画像をRGBに変換
    results = holistic.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))

    if results.pose_landmarks:
      print(
          f'Nose coordinates: ('
          f'{results.pose_landmarks.landmark[mp_holistic.PoseLandmark.NOSE].x * image_width}, '
          f'{results.pose_landmarks.landmark[mp_holistic.PoseLandmark.NOSE].y * image_height})'
      )
    # 画像に姿勢と左手と右手と顔のランドマークを描画
    annotated_image = image.copy()
    mp_drawing.draw_landmarks(
        annotated_image, results.face_landmarks, mp_holistic.FACE_CONNECTIONS)
    mp_drawing.draw_landmarks(
        annotated_image, results.left_hand_landmarks, mp_holistic.HAND_CONNECTIONS)
    mp_drawing.draw_landmarks(
        annotated_image, results.right_hand_landmarks, mp_holistic.HAND_CONNECTIONS)
    # Use mp_holistic.UPPER_BODY_POSE_CONNECTIONS for drawing below when
    # upper_body_only is set to True.
    mp_drawing.draw_landmarks(
        annotated_image, results.pose_landmarks, mp_holistic.POSE_CONNECTIONS)
    cv2.imwrite('/tmp/annotated_image' + str(idx) + '.png', annotated_image)

# Webカメラ入力の場合:
cap = cv2.VideoCapture(0)
with mp_holistic.Holistic(
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5) as holistic:
  while cap.isOpened():
    success, image = cap.read()
    if not success:
      print("Ignoring empty camera frame.")
      # ビデオをロードする場合は、「continue」ではなく「break」を使用してください
      continue

    # 後で自分撮りビューを表示するために画像を水平方向に反転し、BGR画像をRGBに変換
    image = cv2.cvtColor(cv2.flip(image, 1), cv2.COLOR_BGR2RGB)
    # パフォーマンスを向上させるには、オプションで、参照渡しのためにイメージを書き込み不可としてマーク
    image.flags.writeable = False
    results = holistic.process(image)

    # 画像にランドマークアノテーションを描画
    image.flags.writeable = True
    image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
    mp_drawing.draw_landmarks(
        image, results.face_landmarks, mp_holistic.FACE_CONNECTIONS)
    mp_drawing.draw_landmarks(
        image, results.left_hand_landmarks, mp_holistic.HAND_CONNECTIONS)
    mp_drawing.draw_landmarks(
        image, results.right_hand_landmarks, mp_holistic.HAND_CONNECTIONS)
    mp_drawing.draw_landmarks(
        image, results.pose_landmarks, mp_holistic.POSE_CONNECTIONS)
    cv2.imshow('MediaPipe Holistic', image)
    if cv2.waitKey(5) & 0xFF == 27:
      break
cap.release()

5. JavaScript ソリューションAPI

◎ サポートオプション

・upperBodyOnly
・smoothLandmarks
・minDetectionConfidence
・minTrackingConfidence

◎ コード

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/control_utils/control_utils.js" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/holistic/holistic.js" crossorigin="anonymous"></script>
</head>

<body>
  <div class="container">
    <video class="input_video"></video>
    <canvas class="output_canvas" width="1280px" height="720px"></canvas>
  </div>
</body>
</html>
<script type="module">
const videoElement = document.getElementsByClassName('input_video')[0];
const canvasElement = document.getElementsByClassName('output_canvas')[0];
const canvasCtx = canvasElement.getContext('2d');

function onResults(results) {
  canvasCtx.save();
  canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
  canvasCtx.drawImage(
      results.image, 0, 0, canvasElement.width, canvasElement.height);
  drawConnectors(canvasCtx, results.poseLandmarks, POSE_CONNECTIONS,
                 {color: '#00FF00', lineWidth: 4});
  drawLandmarks(canvasCtx, results.poseLandmarks,
                {color: '#FF0000', lineWidth: 2});
  drawConnectors(canvasCtx, results.faceLandmarks, FACEMESH_TESSELATION,
                 {color: '#C0C0C070', lineWidth: 1});
  drawConnectors(canvasCtx, results.leftHandLandmarks, HAND_CONNECTIONS,
                 {color: '#CC0000', lineWidth: 5});
  drawLandmarks(canvasCtx, results.leftHandLandmarks,
                {color: '#00FF00', lineWidth: 2});
  drawConnectors(canvasCtx, results.rightHandLandmarks, HAND_CONNECTIONS,
                 {color: '#00CC00', lineWidth: 5});
  drawLandmarks(canvasCtx, results.rightHandLandmarks,
                {color: '#FF0000', lineWidth: 2});
  canvasCtx.restore();
}

const holistic = new Holistic({locateFile: (file) => {
  return `https://cdn.jsdelivr.net/npm/@mediapipe/holistic/${file}`;
}});
holistic.setOptions({
  upperBodyOnly: false,
  smoothLandmarks: true,
  minDetectionConfidence: 0.5,
  minTrackingConfidence: 0.5
});
holistic.onResults(onResults);

const camera = new Camera(videoElement, {
  onFrame: async () => {
    await holistic.send({image: videoElement});
  },
  width: 1280,
  height: 720
});
camera.start();
</script>

次回



この記事が気に入ったらサポートをしてみませんか?