用Python和MediaPipe实现实时手指识别

开发酷炫的交互应用、控制智能家居,还是进行手语翻译,手指识别 都是其中至关重要的一步。今天,我们将深入探讨如何使用 PythonGoogle 的 MediaPipe 库,快速、精准地实现手指识别功能。

一、MediaPipe 简介:为什么是它?

在计算机视觉领域,手部识别是一个极具挑战性的任务。因为手部经常会出现遮挡、自相似(手指之间很像)以及高自由度的问题。

MediaPipe 是 Google 开源的一个跨平台、多功能多媒体机器学习模型应用框架。它提供了一系列预训练的、开箱即用的模型 ,其中就包括了非常强大的手部姿态估计模型

选择 MediaPipe 进行手指识别的优势:

  • 轻量级且高效:即使在移动设备上也能实时运行。

  • 精准度高:提供了21个手部关键点的3D坐标,足以精确描述手部姿态。

  • 易于使用:几行代码就能集成到你的Python项目中。

  • 强大的鲁棒性:能够处理不同程度的遮挡和光照变化。

二、核心概念:21个手部关键点

MediaPipe 手部模型将一只手抽象为 21个 关键的骨节点,如下图所示。每一个点都有一个固定的索引(0-20)和明确的物理意义。

想象一张图:一只张开的手,上面标记了从0到20的点

  • 0: 手腕

  • 1-4: 拇指根部到指尖

  • 5-8: 食指

  • 9-12: 中指

  • 13-16: 无名指

  • 17-20: 小指

有了这21个点,我们不仅可以知道手的位置,还可以计算出每根手指的弯曲程度、手势的方向等。

三、实战开始:编写你的手指识别程序

让我们一步步构建一个实时的手指识别程序。

步骤 1: 环境搭建

首先,安装必要的库。MediaPipe 的强大之处在于它本身不依赖复杂的深度学习环境。

bash 复制代码
pip install opencv-python mediapipe

步骤 2: 编写核心代码

创建一个Python文件(例如 hand_tracking.py),并输入以下代码:

bash 复制代码
import cv2
import mediapipe as mp

# 初始化MediaPipe手部模型
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles

# 创建Hands对象
# 参数说明:
# static_image_mode: 如果为False,则对视频流进行优化,会追踪检测到的ID以提升性能。
# max_num_hands: 最多检测的手的数量
# model_complexity: 模型复杂度(0或1),1精度更高但更慢
# min_detection_confidence: 检测置信度阈值
# min_tracking_confidence: 追踪置信度阈值
hands = mp_hands.Hands(
    static_image_mode=False,
    max_num_hands=2,
    model_complexity=1,
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5
)

# 打开摄像头
cap = cv2.VideoCapture(0)

while cap.isOpened():
    success, image = cap.read()
    if not success:
        print("Ignoring empty camera frame.")
        continue

    # 为了提高性能,将图像标记为不可写(传递引用)
    image.flags.writeable = False
    # 转换颜色空间 BGR to RGB
    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    # 处理图像并检测手部
    results = hands.process(image_rgb)

    # 将图像标记为可写,以便绘制
    image.flags.writeable = True
    image = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR)

    # 如果检测到手部
    if results.multi_hand_landmarks:
        for hand_landmarks in results.multi_hand_landmarks:
            # 1. 绘制手部关键点和连接线
            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()
            )
            
            # 2. 【进阶】获取特定关键点坐标并操作
            # 例如,获取食指指尖(索引为8)的坐标
            index_finger_tip = hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP]
            # 将归一化坐标转换为像素坐标
            h, w, c = image.shape
            cx, cy = int(index_finger_tip.x * w), int(index_finger_tip.y * h)
            
            # 在食指指尖画一个红色的圆
            cv2.circle(image, (cx, cy), 10, (0, 0, 255), cv2.FILLED)
            
            # 3. 【进阶】判断手指是否伸直(以食指为例)
            # 思路:比较指尖(8)和指根(5)的Y坐标。如果指尖Y坐标小于指根,则认为手指向上。
            index_finger_pip = hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_PIP] # 第二指节
            index_finger_mcp = hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_MCP] # 指根
            
            if index_finger_tip.y < index_finger_pip.y < index_finger_mcp.y:
                cv2.putText(image, "Index Finger Up", (cx, cy-20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    # 水平翻转图像,获得镜像视图
    image = cv2.flip(image, 1)
    # 显示图像
    cv2.imshow('MediaPipe Hands', image)
    # 按 'q' 键退出
    if cv2.waitKey(5) & 0xFF == ord('q'):
        break

# 释放资源
cap.release()
cv2.destroyAllWindows()

步骤 3: 运行与体验

运行这个脚本,你的摄像头将会打开。向摄像头伸出手,你会看到实时的手部关键点和连接线被绘制出来,食指指尖会有一个红点,并且当食指伸直时,会显示"Index Finger Up"的文字。

四、代码详解与进阶应用
  1. hands.process() 返回值

    • multi_hand_landmarks: 一个包含所有检测到的手的列表。

    • multi_handedness: 提供检测到的手是左手还是右手的信息。

  2. 坐标系统

    • landmark.xlandmark.y归一化坐标(0到1之间),分别表示在图像宽度和高度上的比例。需要乘以图像的实际宽高才能得到像素坐标。

    • landmark.z 表示深度,原点在手腕处。值越小,离摄像头越近。

  3. 如何判断手势?

    代码中展示了判断食指是否伸直的逻辑。你可以扩展这个逻辑来定义更复杂的手势。

    • 判断大拇指张开:比较拇指尖(4)和拇指IP关节(3)的X坐标(或Y坐标,取决于手是左手还是右手)。

    • 判断握拳:检查所有指尖是否都低于它们对应的PIP关节。

  4. 实现捏合手势:计算拇指尖和食指尖的欧几里得距离,如果距离很小,则认为发生了捏合。

    bash 复制代码
    # 示例:计算拇指和食指的捏合
    thumb_tip = hand_landmarks.landmark[mp_hands.HandLandmark.THUMB_TIP]
    index_tip = hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP]
    
    distance = ((thumb_tip.x - index_tip.x) ** 2 + (thumb_tip.y - index_tip.y) ** 2) ** 0.5
    if distance < 0.05: # 阈值需要根据实际情况调整
        cv2.putText(image, "Pinch", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
  5. 手势控制:用手势控制PPT翻页、视频播放/暂停。

  6. 虚拟现实/增强现实:在VR/AR应用中实现更自然的手部交互。

  7. 手语识别:组合多个手势来识别基本的手语单词。

  8. 远程协作:在视频会议中用手势进行标注和指示。

六、结语

MediaPipe 将曾经复杂的计算机视觉任务变得平民化。通过这篇博客,你已经学会了如何用它来搭建一个强大的实时手指识别系统。剩下的,就是发挥你的想象力,去创造下一个惊艳的交互应用了!

动手试试吧! 从修改代码、定义你自己的专属手势开始,感受计算机视觉的魅力。
10. 创意艺术:用手指在空中作画。

相关推荐
weixin_307779132 小时前
破解遗留数据集成难题:基于AWS Glue的无服务器ETL实践
开发语言·云原生·云计算·etl·aws
Highcharts.js2 小时前
时间序列图的“性能陷阱”:Highcharts “金融级”优化方案
前端·python·金融
毕设源码-钟学长2 小时前
【开题答辩全过程】以 基于Java的相机专卖网的设计与实现为例,包含答辩的问题和答案
java·开发语言
简单点好不好2 小时前
大恒相机-mono12-python示例程序
开发语言·python·数码相机
后端小张2 小时前
【JAVA 进阶】SpringAI人工智能框架深度解析:从理论到实战的企业级AI应用开发指南
java·开发语言·人工智能
麦烤楽鸡翅3 小时前
小红书推荐系统(牛客)
java·python·算法·秋招·春招·牛客·面试算法题
MATLAB代码顾问3 小时前
MATLAB实现CNN(卷积神经网络)图像边缘识别
开发语言·matlab·cnn
FJW0208143 小时前
Python函数
开发语言·python
屁股割了还要学3 小时前
【C++进阶】STL-string的简单实现
c语言·开发语言·数据结构·c++·学习·考研