🤖 LateAI
首页项目列表 › 手势追踪
🖐️

手势追踪

Hand Tracking
📶 入门 ⏱ 1~2 小时 💰 免费(纯软件) 🏷 CV Zone

📌 项目介绍

手势追踪是 CV Zone 最经典的入门项目:用摄像头实时检测手部,并定位 21 个手部关键点(指尖、指节、腕部等)。

底层用 Google 的 MediaPipe 手部模型 + OpenCV 采集画面,视频作者封装成 cvzone 库的 HandTrackingModule,几行代码就能跑通。后续的虚拟鼠标、虚拟画家、手指计数等项目都建立在这个模块之上,所以它被视作手势应用的基石。

🔬 原课深化 · 原理与模块

① 手部 21 个关键点怎么看

MediaPipe 把每只手输出 21 个关键点,编号固定:0 是手腕;1~4 是拇指(4 为拇指尖);5~8 是食指(8 为食指尖);9~12 是中指(12 为中指尖);13~16 是无名指(16 为无名指尖);17~20 是小指(20 为小指尖)。

记住「指尖索引 = 4 / 8 / 12 / 16 / 20」这条规律,后续虚拟鼠标、手指计数、音量控制所有项目都在取这些点做几何判断。

② HandDetector 封装了什么

cvzone 的 HandTrackingModule 把三件事封装成了几行 API:跑 MediaPipe Hands 模型推理 → 把归一化坐标还原成画面像素坐标 → 顺手整理成字典返回。

每只手返回的字典含 4 个键:lmList(21 个点的 [x, y, z] 列表)、bbox(手部边界框 x/y/w/h)、center(掌心坐标)、type(Left/Right)。

它就是本站其余十几个手势项目的公共底座——先学这一篇,等于一次性掌握了虚拟鼠标、虚拟画家、手指计数的检测部分。

③ 识别原理(通俗版)

MediaPipe Hands 分两步:先用一个轻量网络在整幅画面里定位手的位置(棕榈检测),再对裁剪出的手部区域做关键点回归;一旦检测到,后续帧走更快的跟踪通路,所以能轻松跑到实时帧率。

trackCon 与 detectionCon 两个置信度就是控制「跟踪」与「重新检测」切换的阈值:手跟丢(置信度跌破 trackCon)时会自动退回完整检测。

🧰 环境与物料

🔧 步骤拆解

1

安装环境

创建虚拟环境后执行 pip install opencv-python mediapipe cvzone

安装较慢时用国内镜像源加速

2

摄像头取流

用 OpenCV 的 VideoCapture(0) 打开摄像头

逐帧读取后用 flip 镜像画面,操作更自然

3

初始化手部检测器

从 cvzone 导入 HandTrackingModule 并实例化

关键参数:静态模式、最大手数(默认 1 只)、检测置信度

4

检测并画点连线

每帧调用 findHands() 返回关键点坐标

drawLandmarks 会在画面上画出 21 个点与骨架连线

5

获取单点坐标

用 lmList 拿到每个关键点的 (x, y) 像素坐标

通过索引取指尖等关键位置,供后续逻辑使用

6

封装与后续扩展

把检测逻辑封装成函数/类,方便复用

这个模块就是虚拟鼠标、画家、音量控制的底座

💻 完整代码示例

代码 1 · 最小可运行版(画骨架 + 标出食指尖)
# 依赖:pip install opencv-python mediapipe==0.10.14 cvzone
# 注意:cvzone 当前使用 mediapipe 旧版 Hands API,
#       直接装最新版 mediapipe 会找不到解决方案,务必固定 0.10.14
import cv2
from cvzone.HandTrackingModule import HandDetector

cap = cv2.VideoCapture(0)                # 打开摄像头(0 为默认摄像头)
detector = HandDetector(detectionCon=0.8, maxHands=1)   # 检测置信度 0.8,最多 1 只手

while True:
    ok, img = cap.read()                 # 逐帧读取
    if not ok:
        break
    img = cv2.flip(img, 1)               # 水平镜像,像照镜子一样自然

    hands, img = detector.findHands(img) # 检测并绘制 21 点骨架,返回手部信息列表

    if hands:
        hand = hands[0]
        lmList = hand["lmList"]          # 21 个关键点 [[x, y, z], ...],z 为深度
        bbox   = hand["bbox"]            # (x, y, w, h)
        cx, cy = hand["center"]          # 掌心中心
        tip    = lmList[8][:2]           # 食指指尖坐标(索引 8)
        cv2.circle(img, tip, 8, (0, 255, 255), cv2.FILLED)  # 黄色高亮食指尖

    cv2.imshow("Hand Tracking", img)
    if cv2.waitKey(1) & 0xFF == ord("q"):  # 按 q 退出
        break

cap.release()
cv2.destroyAllWindows()
代码 2 · 多只手 + 指尖标记 + 标注左右手
import cv2
from cvzone.HandTrackingModule import HandDetector

cap = cv2.VideoCapture(0)
detector = HandDetector(detectionCon=0.8, maxHands=2)   # 最多同时检测 2 只手

while True:
    ok, img = cap.read()
    if not ok:
        break
    img = cv2.flip(img, 1)
    hands, img = detector.findHands(img)   # findHands 默认已画出骨架与框

    if hands:
        for hand in hands:
            # 五个指尖索引:拇指4 食指8 中指12 无名指16 小指20
            for i in [4, 8, 12, 16, 20]:
                x, y = hand["lmList"][i][:2]
                cv2.circle(img, (x, y), 7, (0, 255, 0), cv2.FILLED)
            x, y = hand["bbox"][:2]
            cv2.putText(img, hand["type"], (x, y - 10),
                        cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 255), 2)

    cv2.imshow("Hand Tracking", img)
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()

⚙️ 关键参数说明

参数默认作用与建议
staticModeFalse是否每一帧都做完整检测。False 时检测到手后进入跟踪模式,帧率更高;True 适合手不动、需要最高稳定性的场景,但更耗 CPU。
maxHands2画面中最多检测的手的数量。只做单指控制类应用可设为 1,省算力。
modelComplexity1模型复杂度 0 或 1,越大关键点越准但越慢。普通笔记本用默认 1 即可。
detectionCon0.5初次检测的置信度阈值(0~1)。检测不到手时适当降到 0.5~0.6 更易检出,但过低会引入误检。
trackCon0.5帧间跟踪的置信度阈值。跟丢后会自动切回完整检测,一般无需修改。

💡 要点提示

🧯 常见问题排查

安装 mediapipe 后导入失败 / 报找不到 Hands?

新版 mediapipe(0.10.20+)已移除旧版 solutions.hands 接口,而 cvzone 目前仍依赖旧接口。请固定安装:pip install mediapipe==0.10.14,且 Python 用 3.8~3.11(3.12+ 旧版 mediapipe 无预编译包)。

摄像头正常但一直检测不到手?

按顺序排查:① 光照是否均匀(强逆光几乎必失败,侧光最佳);② 手与镜头距离 30~80cm、完整入画;③ 把 detectionCon 从 0.8 降到 0.5~0.6 再试;④ 确认没有把 maxHands 设成 0。

画面很卡、CPU 占用高?

把摄像头分辨率调到 640×480;保持 staticMode=False;不需要画骨架时用 findHands(img, draw=False) 跳过绘图开销;减少同时检测的手数。

左右手 type 反了?

type 是按「画面中的成像位置」标注的(非你身体的实际左右)。开镜像后感觉相反是正常现象;逻辑里若按真实左右手判断(如手势操作),把两值互换或用食指根部 x 与掌心 x 的关系自行判定即可。

lmList 的点坐标是什么单位?

lmList 是像素坐标 [x, y, z]:x、y 为画面像素位置,z 为相对深度的归一化值(手腕为 0,可用来判断手指是否朝镜头弯曲)。做画布/屏幕映射时直接用 x、y。

📦 原站课程与全部资料

查看原站 ↗ ← 返回 LateAI 首页