问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

基于OpenCV的手势鼠标开发指南(包含完整程序)

创作时间:
作者:
@小白创作中心

基于OpenCV的手势鼠标开发指南(包含完整程序)

引用
CSDN
1.
https://blog.csdn.net/weixin_52233146/article/details/146181755

使用Python和OpenCV实现隔空控制鼠标的炫酷功能!本文将手把手教你用Python开发一个基于OpenCV的手势鼠标程序。无需硬件基础,只需普通摄像头+50行代码,即可实现《钢铁侠》般的科技体验!

技术栈全景

核心框架介绍

框架名称
作用说明
官方文档
OpenCV
实时视频处理/图像渲染
opencv.org
MediaPipe
高精度手部关键点检测
mediapipe.dev
PyAutoGUI
跨平台鼠标控制
pyautogui.readthedocs.io
NumPy
三维空间坐标计算
numpy.org

OpenCV核心功能应用

# 摄像头初始化
cap = cv2.VideoCapture(0)  # 0代表默认摄像头
# 图像处理三件套
frame = cv2.flip(frame, 1)                 # 镜像翻转(重要!)
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # 颜色空间转换
cv2.imshow('Hand Tracking', frame)         # 实时显示画面

环境配置

安装必备库

pip install opencv-python mediapipe pyautogui numpy

硬件检查

需要确认摄像头可用

开发环境配置

  • Python 3.6+(建议3.8)
  • IDE选择:PyCharm

手势功能

  • 保持手掌与摄像头距离30-50cm
  • 确保中指伸直用于光标控制
  • 练习OK手势(拇指与食指轻触)

核心实现原理

手部关键点拓扑

关键点索引说明:
这个程序中主要使用了下面三个点位

  • 4号点:拇指指尖
  • 8号点:食指指尖
  • 12号点:中指指尖

坐标映射算法

# 将摄像头坐标转换为屏幕坐标
h, w = frame.shape[:2]  # 获取摄像头分辨率
screen_x = np.interp(curr_x, [0, w], [0, screen_w])  # X轴映射
screen_y = np.interp(curr_y, [0, h], [0, screen_h])  # Y轴映射

手势识别逻辑

def is_ok_gesture(landmarks):
    # 获取三维坐标
    thumb = landmarks[4]  # 拇指指尖
    index = landmarks[8]  # 食指指尖
    
    # 计算3D欧氏距离
    distance = np.sqrt(
        (thumb.x - index.x)**2 +
        (thumb.y - index.y)**2 + 
        (thumb.z - index.z)**2
    )
    return distance < 0.03  # 经验阈值

初始化模块

pyautogui.FAILSAFE = False  
# 配置MediaPipe检测参数
hands = mp_hands.Hands(
    max_num_hands=1,               # 单手势检测
    min_detection_confidence=0.7,  # 识别置信度
    min_tracking_confidence=0.5    # 跟踪灵敏度
)

平滑滤波算法

# 移动平均滤波(有效消除抖动)
smoothening = 3  # 滤波系数(越大越平滑)
curr_x = prev_x + (new_x - prev_x)/smoothening
curr_y = prev_y + (new_y - prev_y)/smoothening

完整程序 main.py

import cv2
import mediapipe as mp
import pyautogui
import numpy as np

# 禁用 PyAutoGUI 的 fail-safe 功能
pyautogui.FAILSAFE = False

# 初始化MediaPipe手部检测模块
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(
    max_num_hands=1,  # 只检测一只手
    min_detection_confidence=0.7,
    min_tracking_confidence=0.5
)

# 获取屏幕分辨率
screen_w, screen_h = pyautogui.size()

# 鼠标灵敏度系数 (根据实际需要调整)
sensitivity = 1.0  # 调整灵敏度,减少这个值以增大控制区域

# 初始化摄像头
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# 平滑滤波参数
smoothening = 3
prev_x, prev_y = 0, 0
curr_x, curr_y = 0, 0

def is_ok_gesture(hand_landmarks):
    """判断是否为OK手势(拇指指尖与食指指尖距离小于阈值,且中指指尖与食指第二关节距离大于阈值)"""
    thumb_tip = hand_landmarks.landmark[4]
    index_tip = hand_landmarks.landmark[8]
    middle_tip = hand_landmarks.landmark[12]
    index_pip = hand_landmarks.landmark[6]
    # 计算3D距离
    thumb_index_distance = np.sqrt(
        (thumb_tip.x - index_tip.x) ** 2 +
        (thumb_tip.y - index_tip.y) ** 2 +
        (thumb_tip.z - index_tip.z) ** 2
    )
    middle_index_distance = np.sqrt(
        (middle_tip.x - index_pip.x) ** 2 +
        (middle_tip.y - index_pip.y) ** 2 +
        (middle_tip.z - index_pip.z) ** 2
    )
    return thumb_index_distance < 0.03 and middle_index_distance > 0.05

while cap.isOpened():
    success, frame = cap.read()
    if not success:
        continue
    # 镜像翻转
    frame = cv2.flip(frame, 1)
    # 转换为RGB格式
    rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    # 手部检测
    results = hands.process(rgb_frame)
    if results.multi_hand_landmarks:
        for hand_landmarks in results.multi_hand_landmarks:
            # 获取中指指尖关键点(控制鼠标移动)
            middle_finger_tip = hand_landmarks.landmark[mp_hands.HandLandmark.MIDDLE_FINGER_TIP]
            # 坐标转换(摄像头坐标 -> 屏幕坐标)
            h, w, _ = frame.shape
            curr_x = middle_finger_tip.x * w
            curr_y = middle_finger_tip.y * h
            # 应用平滑滤波
            curr_x = prev_x + (curr_x - prev_x) / smoothening
            curr_y = prev_y + (curr_y - prev_y) / smoothening
            # 计算屏幕坐标
            screen_x = np.interp(curr_x, (0, w), (0, screen_w))
            screen_y = np.interp(curr_y, (0, h), (0, screen_h))
            # 移动鼠标
            pyautogui.moveTo(screen_x, screen_y)
            # 显示鼠标位置
            cv2.putText(frame, f'Mouse Pos: ({int(screen_x)}, {int(screen_y)})',
                        (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
            prev_x, prev_y = curr_x, curr_y
            # 检测OK手势
            if is_ok_gesture(hand_landmarks):
                pyautogui.click()
                cv2.putText(frame, "OK Gesture Detected", (10, 50),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
            # 绘制手部关键点
            mp.solutions.drawing_utils.draw_landmarks(
                frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
    # 显示调试画面
    cv2.imshow('Hand Tracking', frame)
    # 退出条件
    if cv2.waitKey(5) & 0xFF == 27:
        break

cap.release()
cv2.destroyAllWindows()
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号