はじめに
マウスやキーボードを使わずに、手の動きだけでコンピュータを操作できたら便利だと思いませんか?映画「マイノリティ・リポート」のような近未来的なインターフェースを、たった3つのPythonライブラリで実現できます。
この記事では、OpenCV、MediaPipe、NumPyを使って、Webカメラベースのハンドジェスチャー制御デスクトップUIを構築する方法を解説します。
読了時間:約5分
このプロジェクトで実現できること
- ✋ 手の動きでカーソル操作
- 👌 ピンチジェスチャーでクリック
- ⌨️ 仮想キーボードでテキスト入力
- 🌐 ブラウザ起動とGoogle検索
- 🎮 両手を使ったボールバウンスゲーム
必要なライブラリ
pip install opencv-python mediapipe numpy
たったこれだけ!それぞれの役割:
- OpenCV: カメラ映像の取得と画像処理
- MediaPipe: Googleが開発した高精度なハンドトラッキング
- NumPy: 数値計算とデータ処理
技術的な仕組み
1. ハンドトラッキングの基礎
MediaPipeは、1つの手につき 21個のランドマーク(特徴点) を検出します。
import mediapipe as mp
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(
max_num_hands=2,
min_detection_confidence=0.7,
min_tracking_confidence=0.5
)
重要なランドマーク:
- ランドマーク4: 親指の先端
- ランドマーク8: 人差し指の先端
- ランドマーク0: 手首
2. カーソル制御のロジック
人差し指の先端(ランドマーク8)をカーソル位置として使用します。
def map_to_ui(x, y, cam_width, cam_height):
"""カメラ座標をUI座標に変換"""
ui_x = int(x * UI_WIDTH)
ui_y = int(y * UI_HEIGHT)
return np.clip(ui_x, 0, UI_WIDTH - 1), np.clip(ui_y, 0, UI_HEIGHT - 1)
# 人差し指の先端を取得
index_tip = hand_landmarks.landmark[8]
cursor_pos = map_to_ui(index_tip.x, index_tip.y, cam_width, cam_height)
3. クリック検出:ピンチジェスチャー
親指と人差し指の距離を計算し、閾値以下ならクリックと判定します。
def detect_pinch(hand_landmarks, frame_width, frame_height):
"""ピンチジェスチャーを検出"""
thumb_tip = hand_landmarks.landmark[4]
index_tip = hand_landmarks.landmark[8]
# 2点間の距離を計算
distance = np.sqrt(
(thumb_tip.x - index_tip.x)**2 +
(thumb_tip.y - index_tip.y)**2
) * frame_width
return distance < PINCH_THRESHOLD # 例: 40ピクセル
4. インタラクティブなボタンUI
ボタンをクラスとして定義し、ROI(Region of Interest・関心領域)を管理します。
class Button:
def __init__(self, x, y, w, h, label, action):
self.x, self.y, self.w, self.h = x, y, w, h
self.label = label
self.action = action # クリック時に実行する関数
self.is_hovered = False
def contains(self, px, py):
"""カーソルがボタン内にあるか判定"""
return self.x <= px <= self.x + self.w and \
self.y <= py <= self.y + self.h
def click(self):
"""ボタンがクリックされた時の処理"""
if self.action:
self.action()
ホバーとクリックで色を変えることで、視覚的なフィードバックを提供します。
5. 仮想キーボードの実装
QWERTYレイアウトを2次元配列で定義し、動的にボタンを生成します。
keyboard_keys = [
['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'],
['Z', 'X', 'C', 'V', 'B', 'N', 'M'],
['SPACE', 'BACK', 'ENTER']
]
for row_idx, row in enumerate(keyboard_keys):
for col_idx, key in enumerate(row):
x = start_x + col_idx * (KEY_SIZE + KEY_MARGIN)
y = start_y + row_idx * (KEY_SIZE + KEY_MARGIN)
buttons.append(Button(x, y, KEY_SIZE, KEY_SIZE, key,
lambda k=key: state.type_char(k)))
応用例:ボールバウンスゲーム
両手を検出し、手のひらの中心同士を結んでバーを作成します。
def get_palm_center(hand_landmarks):
"""手のひらの中心を計算"""
palm_points = [0, 5, 9, 13, 17] # 手首と各指の付け根
x_avg = sum(hand_landmarks.landmark[i].x for i in palm_points) / 5
y_avg = sum(hand_landmarks.landmark[i].y for i in palm_points) / 5
return map_to_ui(x_avg, y_avg, cam_width, cam_height)
# 2つの手を検出した場合
if len(results.multi_hand_landmarks) == 2:
palm1 = get_palm_center(results.multi_hand_landmarks[0])
palm2 = get_palm_center(results.multi_hand_landmarks[1])
# バーを描画
cv2.line(frame, palm1, palm2, (0, 255, 255), BAR_THICKNESS)
パフォーマンス最適化のポイント
1. クリックのデバウンス処理
連続クリックを防ぐため、クールダウン時間を設定します。
def can_click(self):
current_time = time.time()
if current_time - self.last_click_time > 0.3: # 300ms
self.last_click_time = current_time
return True
return False
2. FPSの計算と表示
リアルタイムパフォーマンスをモニタリングします。
prev_time = time.time()
current_time = time.time()
fps = 1 / (current_time - prev_time)
prev_time = current_time
3. MediaPipeの設定調整
hands = mp_hands.Hands(
static_image_mode=False, # 動画モード
max_num_hands=2, # 最大検出数
min_detection_confidence=0.7, # 検出信頼度
min_tracking_confidence=0.5 # トラッキング信頼度
)
実装時の注意点
ミラー効果
カメラ映像は左右反転させることで、鏡のような直感的な操作感を実現します。
# カメラ映像を反転
bg = cv2.flip(cam_frame, 1)
照明条件
良好な手の検出には適切な照明が必要です:
- 明るすぎず暗すぎない環境
- 背景とのコントラストを確保
- 逆光を避ける
カメラ解像度
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
高解像度は精度向上につながりますが、処理負荷も増加します。
拡張アイデア
このプロトタイプをベースに、さらに発展させることができます:
- スワイプジェスチャー: 手全体の動きでページ切り替え
- ピンチズーム: 2本指の距離で拡大縮小
- 回転ジェスチャー: 手首の回転でオブジェクト回転
- 音声コマンド統合: ジェスチャーと音声のマルチモーダル操作
- 機械学習: カスタムジェスチャーの学習と認識
まとめ
Pythonと3つのライブラリだけで、マウス不要のハンドジェスチャーUIを実装できました。
ポイント:
- MediaPipeで21個の手のランドマークを高精度検出
- 人差し指の位置でカーソル制御
- ピンチジェスチャーでクリック判定
- ROIベースのボタン管理で拡張性を確保
- 両手の協調動作でより複雑なインタラクション
このプロジェクトは、HCI(ヒューマンコンピュータインタラクション)の入門として最適です。アクセシビリティの向上、VR/ARインターフェース、非接触操作など、様々な応用可能性があります。
サンプルコード
完全なコードはGitHubで公開しています:
https://github.com/Rikiza89/Mirror_Screen_prototype
参考資料
ぜひ試してみて、あなた独自のジェスチャーUIを作ってみてください!質問やフィードバックはコメント欄でお待ちしています。
最後に・・・
この記事が指に馴染んだら、画面の前で『親指(ランドマーク4)』を立てて、ついでに下の『♥️』もピンチしてみてね!🤏✨










