python实现电脑手势识别截图
徐德智联合国展示手势截屏
请看视频!灵感来源。
一、核心功能
实时手势识别:通过 USB 摄像头捕获手部画面,识别手掌的张合状态(从握拳到张开的动作)。
全屏截图触发:当检测到 “从握拳到完全张开” 的手势时,自动截取电脑全屏并保存。
中文界面提示:在摄像头预览窗口中显示中文操作提示(如 “全屏截图已保存”),解决 OpenCV 默认不支持中文的问题。
截图管理:所有截图自动保存在程序目录下的screenshots文件夹中,文件名包含时间戳,避免重复。
二、技术原理
整个程序的工作流程可分为 5 个核心步骤,涉及计算机视觉、手势识别和系统交互技术:
1. 摄像头画面捕获
使用OpenCV库的cv2.VideoCapture(0)调用电脑默认 USB 摄像头,实时获取视频帧(每帧为一张图像)。
视频帧格式为 BGR(OpenCV 默认格式),后续需要转换为 RGB 格式供手势识别模型使用。
2. 手势识别与关键点提取
依赖库:使用 Google 的MediaPipe库实现手部检测,该库提供了预训练的手势识别模型,能高效识别手掌 21 个关键点(如指尖、关节、手腕等)。
关键点检测:
模型处理 RGB 格式的图像,输出手部关键点的坐标(归一化到 0-1 范围,与图像尺寸无关)。
程序中绘制了关键点及连接关系(如mp_drawing.draw_landmarks),方便用户在预览窗口中看到识别效果。
3. 手的张合程度计算
核心逻辑:通过计算指尖到手腕的距离变化,判断手的张合状态。
选取 5 个指尖(拇指、食指、中指、无名指、小指)和手腕的关键点。
计算每个指尖到手腕的欧氏距离(calculate_distance函数),取平均值作为参考。
归一化处理:
将平均距离映射到 0-1 范围(detect_hand_openness函数):
0 表示握拳(指尖到手腕距离最小)。
1 表示完全张开(指尖到手腕距离最大)。
经验值max_distance(0.3)和min_distance(0.1)可根据用户手型调整,优化识别精度。
4. 截图触发条件
检测手势状态的 “突变”:当张合程度从小于 0.3(握拳)突然变为大于 0.7(完全张开)时,触发截图(避免误操作)。
使用pyautogui.screenshot()实现全屏截图,该函数与操作系统无关,可在 Windows/macOS/Linux 上直接获取整个屏幕画面。
解决方法:
自定义put_chinese_text函数,借助matplotlib库绘制中文(matplotlib支持中文字体配置)。
将 OpenCV 的 BGR 图像转换为matplotlib支持的 RGB 格式,绘制中文后再转回 BGR 格式,确保与 OpenCV 窗口兼容。
配置支持中文的字体库(如 SimHei、WenQuanYi Micro Hei),保证不同系统下的兼容性。
三、程序结构说明
初始化部分:
配置 MediaPipe 手势识别模型参数(检测置信度、跟踪置信度等)。
创建screenshots文件夹用于保存截图。
核心函数:
calculate_distance:计算两点间欧氏距离。
detect_hand_openness:计算手的张合程度(0-1)。
capture_full_screen:调用pyautogui实现全屏截图。
put_chinese_text:解决中文显示乱码问题。
主循环(main函数):
实时读取摄像头画面,处理并识别手势。
检测张合状态变化,触发截图并保存。
在预览窗口显示中文提示和识别结果,按q键退出程序。
四、实现代码
import cv2
import mediapipe as mp
import numpy as np
import os
import pyautogui
from datetime import datetime
import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg# 初始化MediaPipe手势识别
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles# 手势关键点索引
THUMB_TIP = 4 # 拇指指尖
INDEX_FINGER_TIP = 8 # 食指指尖
MIDDLE_FINGER_TIP = 12 # 中指指尖
RING_FINGER_TIP = 16 # 无名指指尖
PINKY_TIP = 20 # 小指指尖
WRIST = 0 # 手腕# 创建截图保存目录
if not os.path.exists('screenshots'):os.makedirs('screenshots')def calculate_distance(point1, point2):"""计算两个点之间的欧氏距离"""return np.sqrt((point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2)def detect_hand_openness(hand_landmarks):"""检测手的张合程度,返回0-1之间的值,1表示完全张开,0表示握拳"""# 获取关键点wrist = hand_landmarks.landmark[WRIST]thumb_tip = hand_landmarks.landmark[THUMB_TIP]index_tip = hand_landmarks.landmark[INDEX_FINGER_TIP]middle_tip = hand_landmarks.landmark[MIDDLE_FINGER_TIP]ring_tip = hand_landmarks.landmark[RING_FINGER_TIP]pinky_tip = hand_landmarks.landmark[PINKY_TIP]# 计算各指尖到手腕的距离wrist_thumb_dist = calculate_distance(wrist, thumb_tip)wrist_index_dist = calculate_distance(wrist, index_tip)wrist_middle_dist = calculate_distance(wrist, middle_tip)wrist_ring_dist = calculate_distance(wrist, ring_tip)wrist_pinky_dist = calculate_distance(wrist, pinky_tip)# 平均距离作为张开程度的度量avg_distance = (wrist_thumb_dist + wrist_index_dist +wrist_middle_dist + wrist_ring_dist + wrist_pinky_dist) / 5# 归一化到0-1范围(可根据实际情况调整)max_distance = 0.3 # 完全张开时的最大距离(经验值)min_distance = 0.1 # 握拳时的最小距离(经验值)openness = (avg_distance - min_distance) / (max_distance - min_distance)return max(0, min(1, openness)) # 确保值在0-1范围内def capture_full_screen():"""捕获电脑全屏并返回截图对象"""screenshot = pyautogui.screenshot()return screenshotdef put_chinese_text(img, text, position, font_size=1, color=(0, 255, 0)):# 创建一个与原图大小相同的matplotlib图形fig = plt.figure(figsize=(img.shape[1] / 100, img.shape[0] / 100), dpi=100)canvas = FigureCanvasAgg(fig)ax = fig.add_axes([0, 0, 1, 1])ax.axis('off')# 转换为RGB格式(matplotlib使用RGB)rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)ax.imshow(rgb_img)# 设置中文字体plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]ax.text(position[0], position[1], text, fontsize=font_size * 10,color=(color[2] / 255, color[1] / 255, color[0] / 255), # 转换为RGBbbox=dict(facecolor='none', edgecolor='none'))# 绘制并转换回OpenCV格式canvas.draw()buf = canvas.tostring_rgb()result_img = np.frombuffer(buf, dtype=np.uint8).reshape(img.shape[0], img.shape[1], 3)result_img = cv2.cvtColor(result_img, cv2.COLOR_RGB2BGR)plt.close(fig) # 关闭图形释放资源return result_imgdef main():# 初始化摄像头cap = cv2.VideoCapture(0) # 0表示默认摄像头# 手势状态变量prev_openness = 0screenshot_requested = Falsescreenshot_count = 0with mp_hands.Hands(model_complexity=1,min_detection_confidence=0.7,min_tracking_confidence=0.7) as hands:while cap.isOpened():success, image = cap.read()if not success:print("无法获取摄像头画面。")continue# 转换为RGB并处理图像image.flags.writeable = Falseimage_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)results = hands.process(image_rgb)# 绘制手势标记并检测张合状态image.flags.writeable = Trueimage = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR)openness = 0if results.multi_hand_landmarks:for hand_landmarks in results.multi_hand_landmarks:# 绘制手部关键点mp_drawing.draw_landmarks(image,hand_landmarks,mp_hands.HAND_CONNECTIONS,mp_drawing_styles.get_default_hand_landmarks_style(),mp_drawing_styles.get_default_hand_connections_style())# 计算张开程度openness = detect_hand_openness(hand_landmarks)# 检测手势张合变化(从闭合到张开)if openness > 0.7 and prev_openness < 0.3:screenshot_requested = Truescreenshot_count += 1prev_openness = openness# 如果请求截图,则捕获全屏并保存if screenshot_requested:# 捕获全屏full_screen_img = capture_full_screen()# 保存截图timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")filename = f"screenshots/fullscreen_{timestamp}_{screenshot_count}.png"full_screen_img.save(filename)print(f"全屏截图已保存: {filename}")# 显示中文提示(使用自定义函数)image = put_chinese_text(image, "全屏截图已保存!", (50, 50), 1, (0, 255, 0))screenshot_requested = False# 显示张开程度和操作提示(使用自定义中文绘制函数)image = put_chinese_text(image, f"张开程度: {openness:.2f}", (10, 30), 1, (0, 255, 0))image = put_chinese_text(image, "将手从握拳状态张开以截取全屏", (10, image.shape[0] - 20), 0.7, (255, 0, 0))image = put_chinese_text(image, "按 'q' 退出", (image.shape[1] - 150, image.shape[0] - 20), 0.7,(0, 0, 255))# 显示摄像头画面(用于手势识别预览)cv2.imshow('手势控制全屏截图', image)# 按q退出if cv2.waitKey(5) & 0xFF == ord('q'):break# 释放资源cap.release()cv2.destroyAllWindows()if __name__ == "__main__":main()
五、效果展示

手势识别效果展示
六、使用场景与扩展
适用场景:演示、教学、游戏等需要快速截图的场景,无需手动按快捷键(如PrtSc)。
扩展方向:
不同手势下设备间蓝牙互联进行手势滑动传输。
增加更多手势(如比 “OK” 手势截取窗口、挥手翻页等)。
优化张合程度的阈值参数,适应不同光线和手型。
增加截图预览或编辑功能。
