手でマウスの代わり。人差し指でマウスの動き
親指と指をくっ付けるとクリック。
主にpyautoguiとmediapipeライブラリを使用。
import os
import cv2
import mediapipe as mp
import pyautogui
import numpy as np
# GPU 無効化
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
# Mediapipe 設定
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
hands = mp_hands.Hands(max_num_hands=1, min_detection_confidence=0.7, min_tracking_confidence=0.7)
# 画面サイズ取得
screen_width, screen_height = pyautogui.size()
# カメラ設定
cap = cv2.VideoCapture(3) # 0: 内蔵カメラ / 1: 外部カメラ
# カーソル移動用
prev_x, prev_y = screen_width // 2, screen_height // 2
# クリック判定フラグ
is_clicking = False
# 画面中央80%の範囲に制限するための設定
MIN_RATIO = 0.1 # 10% のマージン
MAX_RATIO = 0.9 # 90% の範囲
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 画像の反転(鏡のようにする)
frame = cv2.flip(frame, 1)
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# 手の検出
result = hands.process(rgb_frame)
if result.multi_hand_landmarks:
for hand_landmarks in result.multi_hand_landmarks:
# ランドマーク描画
mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
# 各指のランドマーク取得
index_tip = hand_landmarks.landmark[8] # 人差し指の先端
thumb_tip = hand_landmarks.landmark[4] # 親指の先端
# **座標を中央80%の範囲にマッピング**
norm_x = (index_tip.x - MIN_RATIO) / (MAX_RATIO - MIN_RATIO)
norm_y = (index_tip.y - MIN_RATIO) / (MAX_RATIO - MIN_RATIO)
# 範囲外なら制限
norm_x = max(0, min(1, norm_x))
norm_y = max(0, min(1, norm_y))
# マウス座標変換
x, y = int(norm_x * screen_width), int(norm_y * screen_height)
# カーソル移動のスムージング(少し前の位置を影響させる)
cursor_x = int(prev_x * 0.7 + x * 0.3)
cursor_y = int(prev_y * 0.7 + y * 0.3)
# カーソル移動
pyautogui.moveTo(cursor_x, cursor_y)
prev_x, prev_y = cursor_x, cursor_y
# クリック(人差し指と親指が近づいたら)
distance_click = np.linalg.norm(np.array([index_tip.x, index_tip.y]) - np.array([thumb_tip.x, thumb_tip.y]))
if distance_click < 0.04 and not is_clicking:
is_clicking = True
pyautogui.click()
print("🖱️ クリック!")
elif distance_click > 0.05:
is_clicking = False # クリック解除
# 画面表示
cv2.imshow("Hand Tracking Mouse", frame)
# ESCキーで終了
if cv2.waitKey(1) & 0xFF == 27:
break
cap.release()
cv2.destroyAllWindows()