资讯动态

基于YOLOv5与MediaPipe的手语识别系统:视频关键点时序分类解析

发布时间:2026/10/5 9:07:03 来源:尧图企业网站定制
简介基于USTC数据集、结合MediaPipe与YOLOv5算法实现的手语视频识别系统Python源码包面向计算机视觉方向的研究者、算法工程师及高校学生适用于手语识别、姿态估计与视频动作分析等场景。资源包含完整的Python项目代码涉及主程序、手部关键点检测、姿态分类、RNN模型、词典映射、界面交互、错误反馈等模块并配有多个测试AVI视频便于本地运行、复现和二次开发。压缩包共42个文件以py源码、ui界面、xml配置、avi视频、png图标为主整体大小约13.77MB目录结构清晰可快速定位核心算法与界面设计部分。已有219人学习下载适合希望了解MediaPipe和YOLOv5协同工作流程、或需要手语识别完整方案的开发者参考。从视频输入、手部关键点提取、序列建模到分类输出代码模块划分相对完整方便读者追踪每个环节的实现细节并在此基础上替换数据集或扩展手势类别也可作为课程设计或毕业设计的参考原型。1. 手语视频识别为什么选 USTC MediaPipe YOLOv5 这套组合手语识别这类项目课程设计里年年有人做但真能跑通的源码包不多。这份基于 USTC 数据集、MediaPipe 和 YOLOv5 的 Python 源码是少见的端到端方案——视频进来先用 YOLOv5 把画面里的手部区域框出来再用 MediaPipe 从区域里提取 21 个手部关键点把连续多帧的关键点序列交给 RNN 做时序分类最后映射到中文手语词汇。它适合三类人要做毕业设计的在校生、想在本地验证手语识别可行性的工程师、需要一套双向交互界面做演示的开发者。我拆包跑了一遍系统同时支持手语转文本和文本转手语测试视频直接丢进去就能看效果。先别急着装依赖这包的坑主要集中在 Python 版本和 YOLOv5 权重上后面细说。2. 系统架构与核心流程从视频帧到 CSL 词汇表的完整链路2.1 双模型分工YOLOv5 负责手部检测MediaPipe 负责关键点回归手语识别的难点在于“手”这个目标很小背景干扰大。USTC 数据集中国科学技术大学手语数据集里的视频手部往往只占画面的一小部分直接对整帧提取关键点结果很不稳定。这个包的做法是把检测和关键点提取拆成两段YOLOv5 在每一帧里输出手部 bounding boxMediaPipe 只在框内区域做 21 点关键点回归。为什么不用 MediaPipe 自带的手掌检测模型有两个原因。第一MediaPipe 自带手掌检测在正面、大手掌场景效果好但 USTC 数据里有大量侧面手和快速运动手势漏检概率高YOLOv5 可以拿 USTC 数据微调换成更贴合手语场景的权重。第二YOLOv5 输出的框可以顺便过滤背景只保留手部区域后续 RNN 拿到的特征更干净。在边缘设备上这种两级流水线还有个好处两边可以分别做加速——YOLOv5 换 TensorRT 或 TFLiteMediaPipe 切轻量模型互不干扰。在 hand_raised_detect.py 里作者针对“举起手做手语”这个场景做了专门处理通过判断手部框的位置和大小把不在画面中央的检测结果过滤掉。手语者通常正对镜头这个先验条件在实际使用中很管用能挡住背景里类似手的目标。YOLOv5 检测阈值参数一般在 conf_thres0.25、iou_thres0.45 附近。conf_thres 太低背景误检变成手部框进而污染关键点iou_thres 太高同一只手会被框两次RNN 输入出现重复特征。这两个值我建议首次跑通后再微调先别动。识别结果为空或乱跳时优先打印 YOLOv5 输出的 bounding box 坐标并叠加画到帧上看框是否贴合手部比盲调超参数更快定位问题。2.2 源码目录拆解main.py、RNN.py、Holistic.py 和 dic 各自的位置这个包有完整的 PyQt5 UI 层和推理层。按我的理解整个目录可以拆成四组分组文件作用入口与界面main.py、myUI/.ui、page/.py程序入口、窗口布局、页面跳转推理核心RNN.py、Holistic.py、Hands.py、PoseClassify.py、OpenPose_1pic.py手语识别、姿态分类工具模块hand_raised_detect.py、dic_processing.py、findFrame.py、draw_pic.py、set_font.py检测辅助、字典处理、切帧、绘图数据与资源dic/dictionary.txt、video/.avi、.png词汇表、测试视频、图标资源main.py 是入口启动后进入 CSL_main.py 主页面。从文件命名能看出系统有两条业务线CSL_to_word.py 和 CSL_to_word_local.py 负责手语视频转文本其中 _local 版本对应本地摄像头输入word_to_CSL.py 负责文本转手语输入文字后从字典匹配并展示对应手语演示。两者共用同一份字典和同一套推理组件差别只在输入源。RNN.py 是时序分类模型被很多人低估。手语是一连串手部动作单帧拿不到语义必须把连续帧的关键点当成时间序列处理。Holistic.py 和 Hands.py 的差别在于Holistic 来自 MediaPipe Holistic同时输出面部、手势、姿态三组关键点Hands 只输出手部 21 点特征维度更低、速度更快。PoseClassify.py 和 OpenPose_1pic.py 负责姿态分类和单帧姿态估计属于辅助模块主要给教学或调试场景用。这套源码还保留了 .idea 目录说明作者是在 PyCharm 下开发的。你用 PyCharm 打开工程时解释器路径可以省一点事但依赖还是要自己配下文的环境部分专门讲。2.3 双向流程手语转文本与文本转手语的数据走向手语转文本这一路video/测试.avi → YOLOv5 检测手部框 → MediaPipe 提取关键点序列 → RNN 分类 → dictionary.txt 查表 → 输出文本。文本转手语是反向输入文本 → 在 dictionary.txt 中匹配索引 → 调取 USTC 数据集对应词条的手语演示 → 在 word_to_CSL 页面播放。这个功能对教学场景很有用相当于一个可交互的电子手语词典。两条路线共存是这个源码包区别于一般手语识别 demo 的关键。大多数开源项目只有识别半条线拿到手只能看结果这套系统至少能双向演示做课程设计答辩时两个方向都能出效果。UI 文件 word_to_CSL.ui、CSL_to_word.ui、CSL_main.ui 是三个独立页面共享底层逻辑改其中一个页面不会影响另外两个。2.4 数据流时序一帧视频从读取到分类输出经历什么以一帧进入 main.py 循环为例执行顺序是读取视频帧 → YOLOv5 前向推理 → 拿手部框 → 对每个框裁剪 → MediaPipe 关键点回归 → 把 63 维向量写入缓冲区 → 缓冲区攒够 seq_len → RNN 前向 → 输出概率分布 → argmax 查字典 → UI 更新文本。注意 RNN 的输入不是一个帧而是一个滑动窗口。常见做法是维护一个 deque 缓冲区每帧 append长度超过窗口就弹出最旧的帧。窗口长度一般取 16 到 32 帧对应视频里 0.5 到 1 秒的动作时长。窗口太短会把一个完整手势动作截断窗口太长又把相邻两个词混在一起分类出现明显错误。MediaPipe 输出的关键点是归一化坐标直接进 RNN 前需要拼接成 63 维。不同帧之间手部位置会位移相同手势的坐标分布会偏移比较正统的处理是减去第一帧的手腕点坐标做相对化。源码未必做了这一步但你复现时发现相同手势识别结果不稳定优先检查这一项。做完这步整个链路就走完了。此时你会发现 UI 层和推理层是分离的CSL_main.ui 只是壳真正的业务逻辑在 page/ 下的脚本里。这种结构对课程设计答辩很有用——老师问代码分层你能指着目录讲明白。3. 环境搭建与依赖安装Python 版本、MediaPipe 和 YOLOv5 权重准备3.1 依赖清单与版本对应关系先说我验证过的环境Windows 11 Python 3.8。为什么用 3.8MediaPipe 在 3.9 以上部分版本存在兼容问题YOLOv5 官方仓库对 3.8 支持最稳。macOS 或 Linux 步骤基本一样把 conda 换成 venv 也行但 MediaPipe 在 Linux 上要额外处理系统库Windows 是最省事的选择。如果本机已经装了其他 Python 版本建议用 conda 单独建一个环境conda create -n csl python3.8 -y conda activate csl python --version核心依赖pip install mediapipe0.10.8 pip install torch2.0.0 torchvision0.15.0 pip install opencv-python4.8.0.76 pip install PyQt55.15.9 pip install numpy pandas scikit-learn参数说明mediapipe 用 0.10.x因为 0.9 及更老版本对 protobuf 的约束与新版 opencv 冲突严重避坑部分细说torch 版本取决于机器有没有 NVIDIA 显卡。有 GPU 就装对应 CUDA 版pip 会自动拉 cuda 运行时没有 GPU 装 CPU 版也能跑只是后面实时性部分会讲到怎么取舍PyQt5 负责 UIword_to_CSL.ui、CSL_main.ui 这些 .ui 文件需要 PyQt5 的 uic 模块加载装完记得验证。一个常见误区是把 opencv-python-headless 和 opencv-python 一起装两个包会互相覆盖文件import cv2 时出现底层错误视频窗口也显示不出来。只保留 opencv-python 就够了。3.2 MediaPipe 安装与 protobuf 冲突处理MediaPipe 的安装坑几乎每个第一次用的人都会遇到。经典报错TypeError: Descriptors cannot not be created directly.原因是 MediaPipe 依赖的 protobuf 版本范围很窄而 opencv-python 或 PyTorch 会联动升级 protobuf导致版本不匹配。解决方式pip install protobuf3.20,4.0但要注意不要一把梭pip install mediapipe就完事。我一般先装 mediapipe再装 opencv-python接着验证python -c import mediapipe as mp; print(mp.__version__) python -c import cv2; print(cv2.__version__)预期输出分别为 0.10.8 和 4.8.0.76。两条 import 都成功、不报错再继续装 PyQt5。这样逐步隔离问题避免最后报错时不知道是哪一步引入的。如果 import mediapipe 依然报错用pip show protobuf查版本手动固定到 3.20.3。3.3 YOLOv5 权重加载与验证YOLOv5 在本项目里负责手部检测。如果源码包没带权重你需要下载 yolov5s.pt或让 torch.hub 指向本地import torch model torch.hub.load(ultralytics/yolov5, yolov5s, pretrainedTrue) model.conf 0.25 # 置信度阈值低于该值的框直接丢弃 model.iou 0.45 # NMS 的 IoU 阈值控制重复框合并参数说明pretrainedTrue 用官方 COCO 权重做通用检测如果你用 USTC 子集微调过手部检测可以换成自定义 best.pt 路径torch.hub 的 custom 模式加载。设备选择上model.cuda()用 GPU 推理单帧毫秒级CPU 推理单帧 30~80ms 波动实测大概 8~12 FPS读取测试视频够用实时 demo 会卡。如果加载权重时报RuntimeError: No such operator torchvision::nms多半是 torch 与 torchvision 版本不匹配按 3.1 的配对版本重装。装完用一段测试视频快速验证模型有没有正常工作import torch model torch.hub.load(ultralytics/yolov5, yolov5s, pretrainedTrue) model.conf 0.25 results model(video/test.avi) print(results.pandas().xyxy[0].head())pandas 输出的每一行是一个检测框包含 x1、y1、x2、y2、confidence、class。如果 class 列全是 person 而没有 hand说明 COCO 权重不支持手部类别后续要靠裁剪和尺寸过滤兜底。这就是很多人第一次卡住的地方YOLOv5 框出了整个人MediaPipe 在整个人区域里找手结果仍可用但速度更慢、误检更多。如果你打算训一套专用手部权重这一步的验证输出就是你最早期的评估指标。4. 核心代码拆解YOLOv5 手部检测、MediaPipe 关键点与 RNN 时序分类4.1 YOLOv5 手部检测置信度阈值、NMS 和裁剪逻辑以 hand_raised_detect.py 为参考推理部分大致这样import cv2 import torch def detect_hands(model, frame): results model(frame) # 输入 BGR 帧内部自动转 RGB boxes results.xyxy[0] # 每行: [x1, y1, x2, y2, conf, cls] hand_boxes [] for box in boxes: x1, y1, x2, y2, conf, cls box.tolist() if conf 0.25: # 置信度阈值可按场景调 h, w frame.shape[:2] # 裁剪时向外留 10 个像素边距避免手腕被截掉 x1 max(0, int(x1) - 10) y1 max(0, int(y1) - 10) x2 min(w, int(x2) 10) y2 min(h, int(y2) 10) hand_boxes.append((x1, y1, x2, y2)) return hand_boxes逻辑说明先跑 YOLOv5 拿到原始检测框再用 conf 过滤低置信度裁剪时向外扩 10 像素是为了防止手部边缘被截断。边框坐标用 max/min 夹到图像范围内避免越界。如果场景里手经常互相遮挡可以把 max_det 调成 3让模型输出多个候选框再过滤。注意这里有一个翻车点如果用的是 COCO 权重模型输出的是 person 框而不是 hand 框宽高比例过滤就很重要把宽高比明显不合理的框丢掉能挡住大部分误检。4.2 MediaPipe Hands/Holistic21 个关键点怎么取MediaPipe Hands 把 21 个手部关键点回归到归一化坐标坐标系相对裁剪区域宽高不是绝对像素。核心代码import cv2 import mediapipe as mp mp_hands mp.solutions.hands hands mp_hands.Hands( static_image_modeFalse, # 视频流模式连续帧跟踪 max_num_hands2, # 最多追踪两只手 min_detection_confidence0.5, # 检测置信度阈值 min_tracking_confidence0.5, # 跟踪置信度阈值 ) def get_hand_keypoints(hand_crop): rgb cv2.cvtColor(hand_crop, cv2.COLOR_BGR2RGB) results hands.process(rgb) if not results.multi_hand_landmarks: return None landmarks results.multi_hand_landmarks[0].landmark kp [] for lm in landmarks: kp.extend([lm.x, lm.y, lm.z]) return kp # 长度 63参数说明static_image_modeFalse 用到了 MediaPipe 帧间跟踪关键点更稳但要求连续视频对测试.avi 没问题单张图片推理要设 True。min_detection_confidence 调高能减少误检漏检也会上升。输出 63 维向量21 点 × xyz这就是 RNN 输入维度对不上会直接 shape 报错。Holistic 模式会额外加面部 468 点和姿态 33 点Holistic.py 就是这么做的。手语识别里面部表情和手臂姿态对语义有补充源码给了两条路径想降特征维度就用 Hands想保留上下文就用 Holistic。实时 demo 我倾向 Hands因为面部关键点在手语视频里对分类贡献有限却占不少推理时间。4.3 RNN 时序建模63 维输入、序列长度与类别映射关键点从单帧变成序列后交给 RNN 分类输入形状是 (batch, seq_len, 63)import torch import torch.nn as nn class CSLRNN(nn.Module): def __init__(self, input_size63, hidden_size128, num_layers2, num_classes200): super().__init__() self.lstm nn.LSTM(input_size, hidden_size, num_layers, batch_firstTrue) self.dropout nn.Dropout(0.3) self.fc nn.Linear(hidden_size, num_classes) def forward(self, x): # x: (batch, seq_len, 63) out, _ self.lstm(x) out out[:, -1, :] # 取最后一个时间步 out self.dropout(out) logits self.fc(out) # (batch, num_classes) return logits参数说明input_size63 与 MediaPipe 输出严格对应seq_len 是截取的动作片段长度一般 16~32 帧太短截断动作太长混入相邻词num_classes 要和 dictionary.txt 统计出的词条数一致设小了报索引越界设大了尾部多出无用节点。推理时连续读帧滑动窗口排队攒够一个窗口就预测一次取 argmax 对应到文本。这个策略对延迟友好比逐帧分类稳定得多。如果发现预测结果频繁跳动可以在 argmax 前加一个 softmax 温度参数压低低置信度类别的输出。4.4 字典处理与输出映射dic_processing.py 的工作细节dic_processing.py 是词汇表核心工具。手语识别输出类别索引要显示给用户得变成可读文本def build_vocab(pathdic/dictionary.txt): word2idx, idx2word {}, {} lines open(path, r, encodingutf-8).read().strip().splitlines() for line in lines: if not line or \t not in line: continue # 跳过空行和非法行 idx, word line.split(\t, 1) # 按制表符切一次 idx int(idx) word2idx[word] idx idx2word[idx] word return word2idx, idx2word注意字典文件如果用的是空格而不是制表符split(\t, 1) 会把整行当成一个词导致 idx 丢失。打开 dictionary.txt 先确认分隔符。如果文件里出现重复索引后出现的词覆盖前面的训练时类别数和实际条数对不上建议加载时用 set 去重并输出警告。RNN 输出 logits.argmax(dim1) 后用 idx2word[pred_idx] 查表pred_idx 要转成 Python int不能是 torch 的 LongTensor否则字典查询直接报错。5. 常见问题与避坑四个高频踩坑点以及对应修复这一节写几条我拆包时实际遇到的问题每条按现象、原因、解决来记方便你对号入座。5.1 MediaPipe 与 OpenCV 的 protobuf 版本冲突现象import mediapipe 直接抛TypeError: Descriptors cannot not be created directly.。原因protobuf 被升级到与 mediapipe 解决器不兼容的版本opencv-python 或 PyTorch 安装时联动升级导致。解决执行pip install protobuf3.20,4.0锁定版本然后重新验证 import。如果还报错把 opencv-python 降到 4.8.0.x 这个线不要追新。装完再跑一次python -c import mediapipe as mp; print(mp.__version__)确认输出是 0.10.8 再继续。5.2 YOLOv5 权重缺失或模型无法加载现象运行到 torch.hub.load 时长时间卡住或者直接报连接超时有的机器报RuntimeError: No such operator torchvision::nms。原因torch.hub 要从 GitHub 拉权重网络不稳定就断流torch 与 torchvision 版本不配对时NMS 算子注册不上。解决先手动下载 yolov5s.pt 放到本地代码改为torch.hub.load(ultralytics/yolov5, custom, pathweights/yolov5s.pt)。NMS 报错就把 torch 和 torchvision 锁定为 2.0.0 和 0.15.0 这对重装后验证 import torch 和 torchvision。这一步别偷懒版本不配对后面所有检测结果都是空的。5.3 测试视频路径中文名导致的解码失败现象cv2.VideoCapture(视频/测试.avi) 返回 False一帧都读不出来改成 video/test.avi 就能正常读。原因OpenCV 在 Windows 上对非 ASCII 路径支持不完整中文目录和文件名会被后端解码成乱码导致打开失败。解决把视频统一重命名为英文文件名放到 video/ 目录下或者先 os.chdir(video) 再读相对路径。源码里的测试视频是中文名这是我第一次跑就遇到的实际问题浪费了小半天。包里的测试.avi、情况.avi、007.avi、004.avi 最好全部改成 test.avi 这种命名再跑。5.4 CPU 推理帧率过低识别延迟明显现象本地摄像头模式CSL_to_word_local.py画面卡顿手部框延迟半秒以上动作结束识别结果才出来。原因YOLOv5、MediaPipe、RNN 三段推理在 CPU 上串行执行单帧总耗时约 90~150ms摄像头输入帧率自然被拖到 10FPS 以下。解决优先把 YOLOv5 的 imgsz 从 640 降到 320这是性价比最高的一步再把 MediaPipe 的 max_num_hands 改成 1、model_complexity 改成 0去掉多余手部追踪。这两步做完CPU 推理帧率能翻倍损掉的精度对手语词汇级别的分类影响不大。如果还不行就放弃实时摄像头改回读取视频文件至少能稳定复现识别结果。6. 验证与扩展技巧用自己的视频样本反向验证系统边界6.1 自建验证样本拍摄手势视频并复用 findFrame.py 切帧拿到源码后很多人的第一反应是拿自己的手势验证。我建议别直接进主流程先用 findFrame.py 把自拍视频切成单帧检查关键点提取质量。一个典型的切帧逻辑import cv2 import os def extract_frames(video_path, out_dir, step4): cap cv2.VideoCapture(video_path) idx 0 frame_id 0 while True: ok, frame cap.read() if not ok: break if idx % step 0: # 每 4 帧抽 1 帧 cv2.imwrite(f{out_dir}/frame_{frame_id:04d}.jpg, frame) frame_id 1 idx 1 cap.release()用与 USTC 风格相仿的手势拍 10 到 20 秒视频抽出 4 到 5 帧查看边界框和关键点。如果手部边缘出现大量断点说明 MediaPipe 置信度和 YOLOv5 阈值需要调这时候再进系统调参比在完整 UI 里盲调快得多。6.2 调低 MediaPipe 阈值或改用轻量模型验证时发现手部关键点抖动把 min_tracking_confidence 从 0.5 降到 0.3帧间平滑会好很多。想提速常见做法是hands mp_hands.Hands( static_image_modeFalse, max_num_hands1, model_complexity0, # 轻量模型 min_detection_confidence0.4, )model_complexity 为 0 的延迟比 1 低很多代价是关键点抖动略大实时 demo 里值得换。6.3 后续改进换 Transformer 或在更大词汇表上验证最直接的扩展是把 RNN.py 换成一个小型 Transformer encoder 做序列分类输入仍是 (batch, seq_len, 63)只是把 LSTM 换成 multi-head attention词汇量大以后泛化明显好一些。另一个方向是拿 USTC 数据集扩充训练集把 dictionary.txt 词表做大。如果你在做多轮手语对话把连续长视频用滑窗切片段就能直接复用当前这套输入格式。项目里 word_to_CSL.ui、CSL_to_word.ui 这些 UI 文件与 page/ 下的脚本一一对应改模型时不要乱动 UI 文件的 objectName。myUI/ 与 page/ 的命名映射一旦错位界面加载会直接白屏。我第一次跑通就在这翻过车。从那以后我每次拿到新源码都会先跑最小用例确认依赖齐、路径对、权重能加载再进 UI 操作。这个顺序我沿用了很多视觉项目希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑