基于YoloV5的手语识别实战:从数据集制作到树莓派部署全流程
发布时间:2026/10/1 1:57:14来源:尧图网络
简介基于YOLOv5的手语识别系统资源包面向计算机视觉学习者和无障碍交互开发者用于解决实时手势检测与手语词汇识别问题。资源共181个文件以XML标注与JPG手势图像为主辅以模型配置、权重检查点、Python训练脚本和使用说明压缩包整体49.17MB目录结构清晰便于按数据、模型、配置模块分段查阅。已有640人学习适合希望从零复现目标检测手语识别流程的读者。内容覆盖图像预处理、YOLOv5特征提取、模型训练与实时推理等关键步骤包含可用的预训练模型与迁移权重、pipeline配置文件、检查点以及protoc等辅助工具可直接用于搭建训练环境、理解标注格式并扩展自定义手势类别。通过阅读源码和配置文件可以掌握从数据集组织到模型调优的完整链路为后续接入智能交互场景提供基础。1. 基于YoloV5的手语识别先想清楚它到底在识别什么做一个基于YoloV5的手语识别系统很多人第一反应是“用目标检测模型翻译手语”这个方向对但容易高估结果。它本质上不是端到端的手语句子翻译而是把“识别”拆成一个目标检测任务对每一帧画面里的手部区域做定位再给这个区域打上类别标签输出“这个手势是数字几”或“这个手型是哪个词”。后续的语句拼接、时序理解要靠上层逻辑做模型本身只负责单帧手型。CVPR上那些端到端手语翻译模型确实做出过惊艳的效果但公开数据集封闭、复现成本高落地时多数团队还是会退回到检测框架——这也是YoloV5在这类项目里被选中的原因训练闭环短单帧精度可控换场景后重训代价小。这个方案适合先落地的场景很明确数字手语、字母手语、固定词表的手势词比如“谢谢”“你好”“要”。它不适合理解语法完整的连续手语句子。如果你手里有树莓派、有摄像头、有几十个类别的采集环境这篇可以帮你从零跑通整个闭环。别一开始就想做全词表先做一个能用的小系统比什么都重要。2. 数据集与标注手语识别的成败在标注框不在网络结构2.1 用公开数据集起步自采数据前先有一个能跑的基线手语识别最花时间的不是训练是数据。YoloV5再强没有贴合场景的数据也白搭。常见做法是先找公开数据集跑通流程再去自采数据扩充。公开数据集里ASLLVD这类偏字母手语RWTH-PHOENIX偏连续句子、需要拆帧标注挑哪个取决于你的词表。注意先看数据集的使用许可很多公开数据仅限科研用途。拿公开数据只是建立基线。你训练出来的模型要在你自己的摄像头、你自己的光照、你自己的拍摄角度下工作公开数据的背景和手型风格往往跟你的现场差异很大。所以我会把公开数据当“预训练素材”用它把网络权重预热一遍再用手工标注的自采数据做微调。这套流程和YoloV5训练自己的数据集的标准做法一致先有个能识别大部分类别的模型再针对短板类别补数据。2.2 自采手势数据采集脚本与三个必须遵守的拍摄纪律自采数据的关键不是数量是覆盖度。一个手势只对着摄像头拍100张不如换五个角度、三个背景各拍20张。采集脚本用OpenCV写很简单我一般会直接抽帧保存import cv2 import os out_dir dataset/raw os.makedirs(out_dir, exist_okTrue) cap cv2.VideoCapture(0) # 0 表示默认摄像头 count 0 while count 500: ret, frame cap.read() if not ret: break cv2.imshow(capture, frame) key cv2.waitKey(1) 0xFF if key ord(s): filename os.path.join(out_dir, fframe_{count:04d}.jpg) cv2.imwrite(filename, frame) count 1 elif key ord(q): break cap.release() cv2.destroyAllWindows()这段脚本的逻辑很简单按s保存当前帧按q退出。count用来控制每个类别采集数量我这里设成500实际不用这么多每个手势300张左右足够起步。关键参数是保存格式用jpg原始帧不压缩后面标注和增强都基于这份原始数据。拍摄时有三个纪律要遵守。第一同一个手势要在不同距离、不同角度各拍一部分手占画面比例大概在30%到70%之间太小了模型学不到细节太大了失去空间上下文。第二背景要换同一块纯色背景拍出来的模型换到真实环境必翻车。第三手指颜色和背景不能太接近肤色和同色系背景会让边界糊成一团。这三个纪律决定了你的标注能不能做下去。2.3 把图片转成YOLO标注转换脚本和标签文件长什么样YoloV5用的不是矩形框坐标加绝对像素而是归一化的中心坐标加宽高。标签文件是每张图片对应一个同名txt文件每行一个目标格式是类别id x_center y_center w h。手工标注我习惯用Labelme它导出JSON格式方便脚本转换。import json import os from glob import glob def labelme_to_yolo(json_path, class_names): with open(json_path, r, encodingutf-8) as f: data json.load(f) image_w data[imageWidth] image_h data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in class_names: continue points shape[points] x1, y1 points[0] x2, y2 points[1] x_center (x1 x2) / 2 / image_w y_center (y1 y2) / 2 / image_h w abs(x2 - x1) / image_w h abs(y2 - y1) / image_h cls_id class_names.index(label) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) return lines if __name__ __main__: class_names [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] for json_file in glob(labels_json/*.json): txt_lines labelme_to_yolo(json_file, class_names) txt_path os.path.join( labels_txt, os.path.basename(json_file).replace(.json, .txt) ) with open(txt_path, w, encodingutf-8) as f: f.write(\n.join(txt_lines))这段转换逻辑里最值得注意的两个细节一是x_center和y_center必须除以图片宽高做归一化二是width和height用绝对值后同样归一化不能直接填像素值。YoloV5在训练时会按imgsz缩放图片如果标签是绝对像素值一旦图片尺寸变化所有框全部错位这是新手最容易踩的坑。class_names的顺序一旦定好就不要改改一次意味着所有标签文件全部要重换id。3. 训练一个自己的手语检测模型环境、超参数与命令3.1 配置yolov5环境conda pip 的免踩坑顺序yolov5环境配置的坑主要出在torch版本和CUDA不匹配。先装PyTorch再装其他依赖顺序反了会出现依赖冲突。我一般用conda建独立环境避免污染系统Pythonconda create -n yolov5 python3.10 -y conda activate yolov5 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118cu118对应CUDA 11.8的wheel源你的显卡驱动如果比较新装这个通常没问题。没有NVIDIA显卡的机器直接pip install torch torchvision装CPU版也能跑通流程只是训练慢很多。装完后建议先验证一次能不能调用GPUimport torch print(torch.cuda.is_available()) # True 则说明GPU可用 print(torch.cuda.get_device_name(0))接下来拿源码和装依赖。写上这一步是因为很多人直接在别处copy项目文件导致缺少组件、版本对不上。标准做法是git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txtrequirements.txt里列了所有运行依赖包括opencv-python、pandas、matplotlib这些。装完跑一下python train.py --help能正常打印参数说明就说明环境通了。整套下来约需10到15分钟剩下的时间基本都会花在数据准备上。依赖装完不建议立即换版本yolov5主干更新较频繁锁定你装好的版本更稳。3.2 训练命令从yolov5s到yolov5m的选择与参数含义之前标注的数据集要整理成yolov5的约定结构图片和txt标签同名放在同一个目录里train和val分开。然后在yolov5目录下写一个数据配置文件# hand_sign.yaml path: /path/to/hand_sign_dataset train: images/train val: images/val nc: 10 names: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]path指数据集根目录train和val是相对根目录的图片文件夹路径。YoloV5会自己去同名txt文件里找标签。nc是类别数names是类别名列表顺序必须和转换脚本里的class_names完全一致错一个就是灾难。训练命令是整套流程的核心python train.py \ --data hand_sign.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --imgsz 640 \ --hyp data/hyps/hyp.scratch-low.yaml \ --device 0逐项说明参数--weights yolov5s.pt指定预训练权重yolov5会自动下载COCO预训练模型手语数据不是COCO类别但预训练权重提供了底层特征提取能力迁移学习效果远好于从头训练。--imgsz 640是训练输入分辨率手语手势目标相对不大640是个平衡点。--batch-size根据显存来调。--hyp指定超参数文件手语这样的小数据集优先用hyp.scratch-low.yaml它做了保守的数据增强训练更稳。如果发现模型检测精度上不去可以把yolov5s.pt换成yolov5m.pt。s和m的区别是网络深度和宽度m更重但精度更高。手语类别粒度细手指微小的弯曲差距决定了类别归属s模型容易在这种细节上丢精度。优先用s跑通流程卡在某个类别精度时再换m。3.3 yolov5超参数里真正值得动的四个参数的含义与调节顺序新手拿到hyp.scratch-low.yaml容易什么都想改我建议先只动四个参数其余保持默认。调参的先后顺序比参数本身更重要。第一个是lr0初始学习率。手语数据集通常只有几千张偏小默认的lr00.01容易震荡收敛不稳可以先降到0.005。判断标准是看训练前几个epoch的loss曲线如果loss在快速跳变就降学习率。第二个是mosaic马赛克增强。yolov5默认mosaic: 1.0它把四张图拼成一张训练。但手语手势本身是小目标拼接后手又被缩得更小反而增加学习难度。我会把mosaic降到0.5左右。若手在画面中占比小、漏检多这个参数优先调。第三个是fliplr水平翻转。COCO上水平翻转能提升泛化性但手语有一个坑手语方向有语义。左手掌朝上表示“要”的时候镜像翻转后可能变成另一个语义的逻辑起点。数字手语相对安全但方向敏感的手势词会被翻转坑到。所以手语识别项目里我一般把fliplr设成0.1甚至0.0。第四个是copy_paste复制粘贴增强。这个参数把目标从一张图复制到另一张图上对目标检测提升明显但手语场景里复制出的“手”可能和背景光影不融合反而制造假样本。建议设置成0.1只做轻量使用。改完超参数后验证方式很简单训练完看验证集mAP同时打开runs/train/exp/confusion_matrix.png看混淆情况。只盯着mAP一个数字会掩盖类别间的差异这在下一章展开讲。4. 手语识别训练避坑指南5个高频翻车现场4.1 类别不平衡常见手语词全被漏检现象训练完mAP看着还行但实际推理时“谢谢”这个类别几乎检测不出来召回率特别低。原因手语词频差异大。常用词你采集得多冷门手势词只拍了一百张导致模型把常见词学得很好冷门词学不动。更隐蔽的是很多人标注时偷懒冷门词只标了一个角度、一个场景模型学到的其实是背景而不手型。解决采集完数据先做一次类别数量统计把低于平均数的类补到中位数的1.5倍以上。另一个做法是在数据yaml里临时提高小类别权重但最根本的还是补数据。每类尽量不要低于200个标注实例。4.2 小目标漏检手在画面里占比太小现象指节动作、手指间的缝隙识别不准检测框完整但类别老错。放大图片人能看清但模型就是分不出来。原因训练时输入尺寸是640手势目标映射到网络特征图只有几十个像素而深度可分离卷积堆叠后小目标的细节特征在前几层就丢了。手语识别对手指间细粒度差异要求很高这正好是目标检测模型的弱项。解决一是把imgsz从640提高到960代价是训练速度变慢、显存占用增加二是把mosaic降下来避免手势在拼接进一步增强中缩得更小三是如果你的手势固定出现在画面中央区域采集时裁出ROI区域再训练去掉无用手部区域的环境干扰。4.3 验证集指标虚高mAP 0.9一部署就现原形现象训练时mAP一路涨到0.9模型放到树莓派或换个摄像头实测识别率直线下降。原因验证集和训练集来自同一时刻、同一摄像头、同一背景下采集的数据背景特征和光照几乎一模一样。模型可能学到的是“某个场景下的手”而不是“手本身”。解决从数据集里单独挑出一个时间段、换一个背景、甚至可以换个不同手型的人专门用来做验证集。验证集建议保持100张以上每类至少10张虽然降低了训练数据量但换来的指标可信度值得。保存模型时以这个独立验证集的mAP为准而不是训练过程里的验证mAP。4.4 两个手势长得太像网络学到的是“像”不是“是”现象数字“6”和“5”经常混淆还有指尖触碰和指尖分离的细微差异类别硬是分不开损失再怎么降都降不动。原因手语里不少词的手型只差一个手指位置在图像上像素级差异很小神经网络很难仅靠外观做出区分。加上标注框位置集中在手部不同类别共享相同的空间位置模型只能在极小的局部特征上找差异。解决先看混淆矩阵找出具体的混淆对然后针对性地采集这些干扰样本。把这对手势训练图裁剪放大同时增加不同手型的采集覆盖。这类问题靠调参解决不明显数据层面做文章才是关键。4.5 训练时显存溢出还没跑几个epoch程序就崩了现象训练到一半报CUDA out of memory进程直接挂掉。原因yolov5的mosaic增强会在一次迭代里拼多张图内存峰值是开mosaic的数倍同时验证阶段也会额外加载模型做推理显存峰值翻倍。解决先把batch-size减半这是最直接的降压手段如果还溢出降低imgsz到480甚至416再不行就在train.py里把--cache参数去掉--cache会预加载所有图片到内存虽然提速但内存开销极大。另外训练前把其他占显存的进程关掉树莓派或嵌入式设备就别想着跑训练了只做推理。5. 推理与部署把检测模型变成可用的手语识别工具5.1 detect.py上手视频与图片推理的最小命令并理解yolov5后处理训练完成后模型在runs/train/exp/weights/best.pt。yolov5源码自带的detect.py可以直接做图片和视频推理输出检测框和类别。最小命令python detect.py \ --weights runs/train/hand_sign/weights/best.pt \ --source demo.mp4 \ --conf-thres 0.4 \ --iou-thres 0.45 \ --max-det 10--source可以是视频文件、图片文件夹或摄像头传0调用默认摄像头。--conf-thres是置信度阈值低于这个概率的检测框被丢弃手语场景里0.4是个比较合理的起点太低会出现大量误检太高会漏检一些拍摄角度偏的样本。--iou-thres是NMS的IoU阈值YoloV5内部会先做解码再做非极大值抑制手语手势不像行人那样互相遮挡框之间重叠少0.45够用设太低会合并不该合并的框。--max-det限制单帧最多输出几个目标。后处理这块yolov5做了不少工作解码、NMS、类别过滤都在这一步完成新手不用自己重新实现一遍。5.2 连续视频流里的一个关键技巧类别平滑单帧检测的抖动是手语识别落地时最常被忽略的问题。手在两根手指之间轻微变化时模型可能在两帧里输出不同类别导致输出“5-6-5-6-5”跳变。处理办法是对检测结果做时间维度上的多数表决。import collections from collections import Counter # 在检测循环外层维护一个最多保留5帧结果的队列 history collections.deque(maxlen5) def smoothed_label(det): history.append(det.cls.cpu().item()) counts Counter(history) label, _ counts.most_common(1)[0] return labeldeque(maxlen5)会自动丢弃最旧的一帧保证队列里永远是最近的5帧结果。most_common(1)取这5帧里出现次数最多的类别作为当前输出。这个技巧能显著平滑识别结果代价是延迟了约5帧的时间实时性要求不高的场景完全可接受。部署树莓派5这类设备时这个平滑逻辑同样适用而且能掩盖一部分模型推理的不稳定。5.3 树莓派5上部署自己的yolov5模型参数取舍与速度平衡树莓派5上跑yolov5s是可行的但必须做推理参数取舍。常见做法是直接用torch加载模型跑推理也可以用export.py转成ONNX或TensorRT加速。最小推理参数调整是把检测尺寸缩到python detect.py \ --weights runs/train/hand_sign/weights/best.pt \ --source 0 \ --imgsz 320 \ --conf-thres 0.5 \ --max-det 1--imgsz 320把输入从640降到320推理速度提升接近4倍代价是小手手势的检测精度下降。--conf-thres 0.5提高到了0.5因为320分辨率下误检率升高需要提高阈值过滤。--max-det 1限制只输出一个目标手语识别场景一帧里一般只关注一个人、一双手这个参数能砍掉大量无用的后处理计算。如果仍然卡顿考虑把模型继续裁剪或做int8量化不过量化后精度下降明显我会优先降分辨率而不是量化。这套流程我做过不止一次最让我吃亏的一次是在自采数据阶段偷懒把所有易混淆手势放在同一个背景同一个角度拍验证集指标高到离谱换了个摄像头部署就直接废掉。重拍一遍之后部署效果才和训练指标对上。从那以后我学到的教训就是数据采集时多花一天胜过训练调试时多花一周。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网