

CT
4月28日


N-S
3月24日


レイ
3月10日

皆さん、はじめまして。プログラマーのCTです。
日々の業務に打ち込んでいるうちに、気づけば入社からそろそろ2年が経とうとしています。
この2年を振り返ると、最初は右も左も分からなかった状態から、少しずつ仕事を任せてもらえることや自力で解決できることが増えてきた実感があります。
とはいえ、学べば学ぶほど『まだまだ知らないことだらけだな』と痛感する毎日でもあります。
日々勉強中ではありますが、今回はそんな中でAI勉強会で使用したMediaPipeについて紹介できればと思います。
MediaPipeは、Googleが開発したオープンソースの機械学習フレームワークで、リアルタイムの映像・音声処理に特化しています。特に、人間の姿勢推定、顔認識、手の検出などのコンピュータビジョンタスクを、高速かつ高精度に実行できることが特徴です。
今回のアプリケーションでは、MediaPipeのHand Landmarker機能を使用しています。この機能により、カメラに映った手の21個の主要な点(指の関節や手のひらの位置)を3次元座標として検出します。
MediaPipeガイド:
MediaPipeは2023年3月1日をもってレガシーソリューションのサポートを終了し、新しいソリューション(MediaPipe Tasks)への移行が行われました。しかし、この新しいソリューションに関する日本語の情報や実装例がまだ少なく、実際に開発を進める際に参考になる記事が不足しているのが現状です。
そこで本記事では、最新のMediaPipe Tasksを使った実践的な実装例として、手の形状認識アプリケーションの使用方法を紹介します。
開発言語:Python 3.12.10
開発エディタ:Visual Studio Code 1.109.2
主要ライブラリ:
mediapipe 0.10.31(Hand Landmarker機能を使用)
opencv-python 4.13.0.90(映像処理)
numpy 2.4.1(データ処理)
まず、必要なPythonライブラリをインストールします。
以下のコマンドをターミナルで実行してください。
各ライブラリの役割
mediapipe:手のランドマーク検出を行う
opencv-python:カメラ映像の取得とフレーム処理
numpy:座標データの配列操作
MediaPipe Tasksでは、事前学習済みのモデルファイル(.taskファイル)をダウンロードする必要があります。
Hand Landmarkerモデルは、先ほど紹介したMediaPipeガイドにアクセスし、『モデル』の項目からダウンロードしてください。
ダウンロードしたファイルをプロジェクトフォルダに保存します。(例:model/hand_landmarker.task)
必要なライブラリをインポートします。
各インポートの説明
cv2:OpenCVでカメラ映像を扱う
mediapipe:MediaPipeのメインパッケージ
mediapipe.tasks.python:新しいMediaPipe Tasksのインターフェース
mediapipe.tasks.python.vision:画像・映像処理用のタスク
numpy:数値計算用
まず、検出結果を非同期で受け取るコールバック関数を定義します。
次に、MediaPipe TasksのHand Landmarkerを初期化します。
パラメータの説明
running_mode(処理モード)
LIVE_STREAM:リアルタイム処理(カメラ映像向け)
VIDEO:動画ファイル処理
IMAGE:静止画処理
num_hands
同時に検出する手の最大数。
各confidence値(0.0〜1.0)
min_hand_detection_confidence:手を検出する際の信頼度閾値
min_hand_presence_confidence:検出した手が存在し続けているかの信頼度閾値
min_tracking_confidence:フレーム間で手を追跡する際の信頼度閾値
値が高いほど検出精度が厳しくなるが、誤検出は減る。
result_callback
LIVE_STREAMモードでは必須のパラメータ。
検出が完了すると自動的にこの関数が呼び出される。
非同期処理により、検出中も次のフレームの処理が可能。
カメラの初期化
パラメータの説明
0:使用するカメラのインデックス(0はデフォルトカメラ)
cv2.CAP_DSHOW:Windows環境でDirectShowを使用し、カメラとの通信を最適化
cv2.CAP_PROP_FRAME_WIDTH:カメラ解像度の横幅
cv2.CAP_PROP_FRAME_HEIGHT:カメラ解像度の縦幅
cv2.CAP_PROP_FPS:カメラの1秒間の画像取得枚数
※パラメータはカメラの性能に合わせて設定してください。
メインループでのフレーム取得と検出
重要なポイント
非同期処理の仕組み
detect_async()を呼び出すと、検出処理がバックグラウンドで開始される。
メイン処理はすぐに次の行に進む。(待機しない)
検出が完了すると、mp_callback()が自動的に呼び出される。
コールバック関数内でdetection_resultに結果が格納される。
タイムスタンプの役割
各フレームを一意に識別するために使用。
ミリ秒単位の整数で指定する必要がある。
datetime.now().timestamp() * 1000で現在時刻をミリ秒に変換。
ミラー表示の理由
cv2.flip(frame, 1)で左右反転
カメラ映像を鏡のように表示することで、ユーザーが直感的に操作しやすくなる
コールバック関数で受け取った検出結果から、手のランドマーク座標を取得します。
検出された手の数を確認
指定した手のランドマーク座標を取得
手の全ランドマーク座標(21個)を取得
手のランドマーク構造
MediaPipeのHand Landmarkerは、手の21個のランドマークを検出します。

出典:Hand landmarker guide | Google AI Edge (Licensed under CC BY 4.0)
各ランドマークは以下の座標を持ちます。
x: 画像の幅を基準とした正規化座標(0.0〜1.0)
y: 画像の高さを基準とした正規化座標(0.0〜1.0)
z: 手首を基準とした深度(負の値は手前、正の値は奥)
検出結果の使用例
検出したランドマーク座標を使って、カメラ映像上に手指の骨格を可視化します。
ランドマーク(関節)の描画
検出された21個のランドマークを円で描画します。
骨格(ランドマーク間の接続)の描画
ランドマーク同士を線で結んで、手の骨格構造を表現します。
グローバル変数の初期化を追加
メインループに組み込む
接続関係の説明
緑色の円:21個のランドマーク(関節の位置)
赤色の線:ランドマーク間の接続(骨格の構造)
が、リアルタイムでカメラ映像上に表示されます。
MediaPipeから取得した座標は正規化座標(0.0〜1.0の範囲)ですが、そのまま使うと問題が発生します。
正規化座標の問題点
MediaPipeのランドマーク座標:
x座標: 画像の幅を基準とした正規化座標(0.0〜1.0)
y座標: 画像の高さを基準とした正規化座標(0.0〜1.0)
例えば、1920×1080の画像(16:9)の場合
x座標の1.0 = 1920ピクセル
y座標の1.0 = 1080ピクセル
つまり、同じ0.1でも、x方向とy方向で実際の距離が異なることになります。
補正方法
補正後の座標の特徴
x座標とy座標が同じスケール(単位距離)になる
指の間の距離や角度の計算が正確になる
機械学習モデルの入力として、より適切なデータになる
実際の使用例
重要なポイント
y座標とz座標は補正不要。(y座標はすでに正規化されている、z座標は相対的な深度)
補正することで、画像の形状に依存しない普遍的なデータが得られる。

本記事では、MediaPipe Tasksを使用した手指検出の実装方法を紹介しました。カメラからリアルタイムに手のランドマーク座標を取得し、画像上に骨格を描画できるようになりました。
今回取得した21個のランドマーク座標を使うことで、以下のような応用も可能です。
手の形判別:グー・チョキ・パーの判定、指の曲げ伸ばしの認識
ジェスチャーコントロール:手の動きでアプリケーションを操作
データ収集:機械学習用の学習データとして座標を保存
最後に、本記事はMediaPipe Tasksの新しいAPIに関する日本語情報が少ない中で、実装の一助となればと思い執筆しました。まだまだ未熟な部分も多く、わかりにくい説明や不足している点もあるかと思いますが、少しでも参考になれば幸いです。
MediaPipeは非常に強力なツールです。本記事をきっかけに、様々な応用に挑戦していただければと思います。
ここまでお読みいただき、ありがとうございました。
完成コード
フォルダ構成
prject
├model
│└hand_landmarker.task
└main.py
main.py






コメント