注釈

こんにちは、SunFounder Raspberry Pi & Arduino & ESP32 Enthusiast Community on Facebookへようこそ!他の愛好家と一緒に、Raspberry Pi、Arduino、ESP32の世界により深く入り込みましょう。

参加する理由

  • 専門家サポート: 購入後の問題や技術的な課題を、コミュニティと私たちのチームの助けを借りて解決します。

  • 学習と共有: ヒントやチュートリアルを交換して、スキルを向上させましょう。

  • 限定プレビュー: 新製品の発表や先行プレビューに早期アクセスできます。

  • 特別割引: 最新製品を特別割引でお楽しみいただけます。

  • 季節限定キャンペーンとプレゼント: プレゼント企画やホリデーキャンペーンに参加しましょう。

👉 一緒に発見し、創造する準備はできましたか? [こちら] をクリックして、今すぐ参加しましょう!

5. 手のジェスチャーカウント

1. 概要

前のセクションでは、リアルタイムの手検出と ランドマークの可視化を実装しました。

このセクションでは、その機能を拡張し、 指のランドマーク位置を利用して 挙げられている指の本数(0~5)をカウントします。

指先と対応する関節の相対位置を分析することで、 各指が伸びているかどうかを判定できます。

../_images/mp_hand_count.png

2. 動作の仕組み

プログラムは次の手順で動作します:

  1. MediaPipe Hands モデルを初期化する

  2. Raspberry Pi カメラから映像フレームを取得する

  3. リアルタイムで 21 個の手ランドマークを検出する

  4. 指先の座標と対応する関節の座標を比較する

  5. 各指が伸びているかどうかを判定する

  6. 挙げられている指の本数をカウントする

  7. 結果を動画フレーム上に表示する

この方法の特徴:

  • 軽量で効率的

  • Raspberry Pi に適している

  • ジェスチャー制御やインタラクティブシステムの基礎となる

3. コードの実行

重要

開始する前に、次の項目を確認してください:

  • パンチルトが組み立てられている

  • Raspberry Pi のデスクトップにアクセスできる

  • コードパッケージがインストールされている

  • Fusion HAT+ がインストールおよび設定されている

  • OpenCV がインストールされている

詳細な手順については 0. OpenCV のセットアップ を参照してください。

  1. ターミナルを開き、次のコマンドを入力します:

    sudo python3 ~/ai-lab-kit/mediapipe/mp_hand_count.py
    
  2. プログラムを実行すると、「Show Video」というタイトルのウィンドウが開き、カメラのライブ映像が表示されます。

    カメラの前に手が現れると:

    • MediaPipe がリアルタイムで手を検出します

    • 手に 21 個のランドマークと接続線が描画されます

    • プログラムが指先と関節の位置を解析します

    • 挙げられている指の本数(0~5)が計算されます

    検出された指の本数は画面左上に次のように表示されます:

    Fingers: X

    指を伸ばしたり曲げたりすると、 数値はリアルタイムで更新されます。

    手が検出されない場合は、 指のカウント表示なしで通常のカメラ映像のみが表示されます。

    q を押すとプログラムを終了できます。 カメラは停止し、OpenCV ウィンドウは自動的に閉じます。

4. 完全なコード

from picamera2 import Picamera2, Preview
import cv2
import mediapipe.python.solutions.hands as mp_hands
import mediapipe.python.solutions.drawing_utils as drawing
import mediapipe.python.solutions.drawing_styles as drawing_styles

# Initialize the Hands model
hands = mp_hands.Hands(
   static_image_mode=False,  # Set to False for processing video frames
   max_num_hands=2,           # Maximum number of hands to detect
   min_detection_confidence=0.5  # Minimum confidence threshold for hand detection
)

# Open the camera
picam2 = Picamera2()
config = picam2.create_preview_configuration(
   main={"size": (640, 480), "format": "XRGB8888"} ,
)

picam2.configure(config)
picam2.start()

print("Streaming... press 'q' to quit")

# Finger tips and dips
finger_tips = [4, 8, 12, 16, 20]
finger_dips = [2, 6, 10, 14, 18]


while True:
   frame_bgra = picam2.capture_array()               # XRGB8888 to BGRA
   frame_bgr  = cv2.cvtColor(frame_bgra, cv2.COLOR_BGRA2BGR)

   # Convert the frame from BGR to RGB (required by MediaPipe)
   frame = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB)

   # Process the frame for hand detection and tracking
   hands_detected = hands.process(frame)

   # Convert the frame back from RGB to BGR (required by OpenCV)
   frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

   # If hands are detected, draw landmarks and connections on the frame
   if hands_detected.multi_hand_landmarks:
      for hand_landmarks in hands_detected.multi_hand_landmarks:
            drawing.draw_landmarks(
               frame,
               hand_landmarks,
               mp_hands.HAND_CONNECTIONS,
               drawing_styles.get_default_hand_landmarks_style(),
               drawing_styles.get_default_hand_connections_style(),
            )


            # Count the number of fingers raised (right hand)
            landmarks = hand_landmarks.landmark
            finger_count = 0

            # Check if thumb is up
            if landmarks[finger_tips[0]].x > landmarks[finger_dips[0]].x:
               finger_count += 1

            # Check if the other fingers are up
            for i in range(1, 5):
               if landmarks[finger_tips[i]].y < landmarks[finger_dips[i]].y:
                  finger_count += 1

            # Display the number of fingers raised
            cv2.putText(frame, f"Fingers: {finger_count}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)


   # Display the frame with annotations
   cv2.imshow("Show Video", frame)

   # Exit the loop if 'q' key is pressed
   if cv2.waitKey(1) & 0xff == ord('q'):
      break

# Release the camera
picam2.stop_preview()
picam2.stop()
cv2.destroyAllWindows()

各ループで 5 本の指が伸びているかどうかを判定し、 伸びている指の数をカウントします。例:

  • ✊ すべての指を閉じる → 0

  • ☝️ 人差し指のみ → 1

  • ✌️ 人差し指+中指 → 2

  • 🖐️ 5 本すべて開く → 5

5. 検出ロジックと拡張

MediaPipe Hands は 21 個のランドマークを返します。 指先と関節の位置を利用して、 各指が伸びているかどうかを判定します。

finger_tips = [4, 8, 12, 16, 20]
finger_dips = [2, 6, 10, 14, 18]
  • finger_tips → 指先のランドマークインデックス (Thumb=4, Index=8, Middle=12, Ring=16, Pinky=20)

  • finger_dips → 対応する関節のランドマークインデックス (Thumb=2, Index=6, Middle=10, Ring=14, Pinky=18)


指カウントのロジック:

landmarks = hand_landmarks.landmark
finger_count = 0

# Check thumb (right hand)
if landmarks[finger_tips[0]].x > landmarks[finger_dips[0]].x:
    finger_count += 1

# Check other four fingers
for i in range(1, 5):
    if landmarks[finger_tips[i]].y < landmarks[finger_dips[i]].y:
        finger_count += 1

cv2.putText(frame, f"Fingers: {finger_count}", (10, 30),
            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

ロジック説明:

  • 親指tip.xdip.x を比較(右手の場合)

  • 他の指tip.ydip.y を比較

  • 指先が関節より上(または外側)にある場合、 その指は伸びていると判断されます

  • 条件を満たすたびに +1 されます


拡張のヒント:

  • 左手と右手の両方に対応する場合は、 hands_detected.multi_handedness を使用して 手の種類を判定し、 親指の x 軸比較を反転させます。

  • このロジックは次のような機能にも拡張できます:

    • OK ジェスチャー認識

    • サムズアップ検出

    • じゃんけんインタラクション

    • カスタムジェスチャー操作

6. トラブルシューティング

  • 親指の検出が不正確

    親指は左右の手で判定ロジックが異なるため、 検出が不正確になることがあります。

    multi_handedness を使用して 左手か右手かを判定し、 親指の検出ロジックを調整してください。

  • 検出が不安定

    指のカウントが不安定な場合、 照明不足または背景が複雑な可能性があります。

    照明を改善し、シンプルな背景を使用すると 検出の安定性が向上します。

  • 遅延が大きい

    応答が遅い場合、 解像度が高すぎるか CPU 負荷が高い可能性があります。

    解像度を下げ(例:320×240)、 不要なバックグラウンドプロセスを終了してください。 必要に応じて指カウントロジックを簡略化することもできます。

7. まとめ

  • MediaPipe Hands を使用すると リアルタイムジェスチャー認識 を簡単に実装できます。

  • 本セクションでは 指の本数ジェスチャー認識 を実装し、 カスタムジェスチャー認識の基礎を構築しました。

  • 左右の手への対応や判定ルールを拡張することで、 より高度なインタラクションシステムを実装できます。