基于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()
热门推荐
VSCode vs GDB:C语言编译错误调试哪家强?
济南市最新古树普查揭秘:千年古树知多少?
济南古树保护黑科技:“古树芯”上线
济南古树名木保护工程:守护千年白皮松
头孢+酒=灾难?服用后多久可以饮酒?还有哪些药物同样致命?
苏州十大特产:从糕点到丝绸的文化之旅
同事之间的人情往来怎么把握分寸
甘露醇:糖尿病食品的新宠儿?
中华医学会发布甘露醇治疗颅内压增高专家共识
甘露醇:医学界的神奇脱水剂
脸部紧致的方法是什么
公安部新规:2025年1月起施行!60岁以上老年人可驾驶八种电动车
GB 1886.177-2016认证:D-甘露糖醇的安全性解析
武汉发布新版产业地图,多区有变化
武汉大学中南医院:一家具有国际影响力的大型综合性医院
苏州一日游攻略:从拙政园到金鸡湖的完美行程安排
如何正确操作离合器?离合器的操作技巧对驾驶安全有何影响?
瑰夏咖啡并无“最佳”产地
2024年车船税计算公式详解:最新政策变化与计算方法
水瓶座男愛一個人的秘密:自由的愛與深厚的情感
一个“失败”的实验,却开启了物理学的新纪元
成都8大景点仍需提前预约,游玩攻略来了!
飞度车主必看:2024年车船税最新算法
阵发性室上性心动过速的治疗方法有哪些
解锁一杯好咖啡的密码
F1上海站周末开赛 地铁上海赛车场站将实施管控
驾照可以终身免检了?车管所:只要满足这3个条件,不妨申请试试
消防员团队协作训练:关键时刻救命的硬功夫
东南亚美食,东南亚各国美食区别
爱因斯坦的"脑洞":光速不变原理如何改变物理学