资讯动态

YOLOv5与YOLOv8骰子点数检测实战:从数据集到部署全流程解析

发布时间:2026/10/20 2:52:31 来源:尧图企业网站定制
周末玩桌面游戏的时候我最烦的不是骰运差而是大家抢着报点数的混乱。做这期骰子识别练习的起因就是这么简单想给桌游计分做一个小工具。最终选的路线就是 YOLO这个项目里除了图片数据集之外还直接给了 YOLOv5 和 YOLOv8 两套模型权重省了我从零搭模型的时间。整件事的核心就是跑通一套“骰子数据集(有v5/v8模型)/YOLO骰子点数检测”的完整流程从数据检查、模型训练到后续的推理部署和点数汇总。这篇记录适合三类人看一是拿这个数据集做课程设计、毕业设计的同学二是想给桌游辅助设备加视觉计分模块的开发者三是跟我一样在 YOLOv5 和 YOLOv8 之间犹豫该怎么选的人。我会把整个处理链路拆开讲包括数据怎么检查、训练参数怎么定、后处理怎么写以及部署现场最容易翻车的几个场景。1. 项目定位与整体流程骰子点数检测能做什么1.1 我为什么做这个项目谁适合参考骰子点数检测说白了就是对画面里的每一颗骰子输出一个边界框同时给出 1 到 6 的点数标签。听起来是通用目标检测的一个小分支实际做起来却有几个特有的坑点数相对于骰子整体来说属于小目标六个类别之间的外观差异又很小两颗骰子叠在一起时边界模糊光照一变化白色圆点可能直接融进背景。这些问题在我平时做通用检测时很少碰到所以专门想找一套成熟数据练手。这个骰子数据集正好满足需求。它提供六个点数的完整标注图片覆盖了不同骰子数量、不同视角、不同桌面背景还附带了 v5/v8 两套模型权重。我拿到手之后先跑了一轮 Demo确认效果再开始做训练和对比。它的意义在于帮你省掉了最耗时的数据采集环节同时留出了足够的多样性不至于像自己随手拍十几张图强行训练那样容易过拟合。适合参考的人群我觉得就三类智能桌游或辅助计分终端的硬件开发者需要完整视觉方案的课程设计学生以及想直观对比 YOLOv5 和 YOLOv8 差异的人。如果你是这三类人之一下面这些步骤基本可以照着抄。1.2 从拿到数据到部署完成完整链路怎么设计我的处理链路分成五步环境准备、数据检查、模型训练、推理验证、功能封装。看上去平平无奇但每一步都有不能省的细节。先说环境准备。YOLOv5 和 YOLOv8 都需要 Python 环境以及 PyTorch、OpenCV 这类基础库。建议提前准备一张显存足够的独立显卡至少保证 batch size 等于 16 时能跑 640 分辨率的训练。没有 GPU 的话用 CPU 跑预训练模型做推理没问题但训练会非常慢训练轮数要适当减少。第二步数据检查一定不能跳。很多人拿到数据集就直接开训等 mAP 出现异常才回头查结果发现是标注问题。正确做法是先统计图片数量、类别分布、标注框尺寸再把标注框画到原图上做人工抽查。这部分我放在下一节细说。第三步是模型训练。项目里带了 v5 和 v8 两套权重我分别以它们为基础做预训练微调记录了训练损失和验证 mAP后面有对应的参数复现记录。第四步是推理验证。训练完成的模型要放到真实桌面上测试把所有检测结果实时画到画面里观察有没有漏检、误检、点数乱报。第五步是功能封装。把模型推理、跨帧跟踪、点数合计整合成一个小工具后面我还接了一个语音播报算是桌游辅助功能的初版。整套流程我花了大概两天跑通但如果跳过第二步或第四步后面返工的时间很可能比训练时间还长。2. 骰子数据集的组织与检查先别急着训练2.1 目录结构与YOLO标注格式可直接用于 YOLO 训练的数据集大多长成一个标准样子images 目录放图片labels 目录放对应的 txt 标注。骰子数据集也不例外目录结构大概长这样dice_dataset/ ├── train/ │ ├── images/ │ │ ├── 001.jpg │ │ └── ... │ └── labels/ │ ├── 001.txt │ └── ... ├── val/ │ ├── images/ │ │ └── ... │ └── labels/ │ └── ... ├── data.yaml └── README.md每一张图片对应一个同名的 txt 文件文件里每一行描述一个目标。行格式是类别编号、归一化中心 x、归一化中心 y、归一化宽度 w、归一化高度 h。所有坐标值都用图片宽高做了归一化范围 0 到 1。举个例子某个 4 点骰子的标注行是3 0.5234 0.4176 0.2178 0.2231。这里类别编号为什么是 3 而不是 4因为 data.yaml 里 names 列表的索引从 0 开始names[0] 对应 1 点names[5] 对应 6 点。类别映射管好之后点数统计逻辑才不会出错。我第一次跑通代码时就是因为没看 data.yaml直接把类别编号当成点数用结果 2 点骰子显示成了 3 点排查了半天。2.2 类别分布和图片质量统计我用脚本统计了数据集的几个关键指标训练集图片大约 2000 张验证集 300 多张一张图里的骰子数量在 1 到 5 颗之间图片分辨率最低 640×640最高 1920×1080。六个类别的框数量相差不大基本均匀分布这个情况对训练很友好。统计代码也不复杂from pathlib import Path names [one, two, three, four, five, six] label_paths list(Path(dice_dataset/train/labels).glob(*.txt)) total 0 class_count [0] * len(names) box_area_sum 0.0 for lp in label_paths: for line in lp.read_text().strip().splitlines(): parts line.split() c int(parts[0]) w float(parts[3]) h float(parts[4]) total 1 class_count[c] 1 box_area_sum w * h print(total boxes:, total) for i, name in enumerate(names): print(f{name}: {class_count[i]}) print(mean box area ratio:, box_area_sum / total)从统计结果能看出骰子目标在整幅图里的占比属于中等偏小。如果把图片统一压到 640 分辨率原本的小骰子区域会变得更小对特征提取有压力。所以训练时至少保持 640 输入不要为了省时间直接降到 320。2.3 可视化抽查发现的标注问题统计只能发现数量异常发现不了语义错误。我把训练集随机抽了 200 张把标注框直接画在图片上逐张看。画框脚本用 OpenCV 就能实现这里只说抽查结论。抽查发现两个值得注意的问题。第一个别图片把骰子的框画得过大把旁边另一颗骰子的一角也包了进来。这种框会让模型在训练时学到错误的目标范围推理时边界框会比骰子实际边缘大一圈。第二少数图片里的点数标签有混淆对比度差的图里4 点骰子和 5 点骰子的标注被弄混了。这类问题靠自动化很难查出来只能人眼扫。如果发现比较多直接修标签或丢掉样本别拿错误数据去折磨模型。修标注的工作量不大但收益很明显。提示标注框不精确时先修正再训练。错框会直接腐蚀模型的回归精度训练后再补救比事前检查慢得多。3. YOLOv5与YOLOv8的实测对比同一份骰子数据下谁更稳3.1 架构差异在骰子检测上意味着什么YOLOv5 和 YOLOv8 虽然同属 YOLO 家族内部差异其实非常大。v5 用的是基于 anchor 回归的检测头训练时会预先设定一系列 anchor 框模型预测的是这些 anchor 与真实框之间的偏移分类和回归在头部结构里是耦合的。v8 换成了解耦检测头分类和回归各自走独立的输出分支并且不再依赖 anchor模型直接在特征图上预测目标中心、宽高和类别。对骰子点数检测来说最大的实际影响在两点一是目标尺寸小二是类别间差异小。v8 的解耦头让分类分支和回归分支不再互相干扰对 1 到 6 点这种相似类别的区分有一定帮助。v5 的 anchor 机制在小目标上表现其实也不错但需要相对合理的 anchor 配置默认配置遇到骰子这种形状规整的目标时够用遇到极端大小差异时会吃亏。另外v8 骨干网络用了 C2f 模块替代 v5 的 C3 模块C2f 在梯度流上更平滑同等计算量下特征表达能力更强。这些架构差异最终会体现在验证指标和实际画面的边界情况上。3.2 mAP与推理速度的实测结果我用同样的数据划分做了一组对比验证结果如下表模型参数量输入分辨率mAP50mAP50-95平均推理延迟yolov5s约 7.3M640×6400.9880.9516.8msyolov8s约 11.2M640×6400.9930.9668.2ms测试环境是同一块支持 CUDA 的显卡关闭了推理加速引擎只对比原始框架下的推理速度。参数量差异体现在模型文件大小上v5s 约 14MBv8s 约 22MB。结论是v8s 在精度尤其是 mAP50-95 上略胜一筹v5s 在速度和模型体积上更占优势。对骰子点数检测这种不需要极端精度的任务来说两者都够用真正决定选择的其实是部署环境。边缘设备或对延迟敏感的场景选 v5s需要更好泛化能力比如面对多变光照和复杂桌面背景v8s 留下的余地更大。3.3 边缘场景中的直观差异指标之外的差异我是用几张比较极端的图片单独试出来的。第一张是强逆光下的黑色骰子v5s 能框出来但类别置信度只有 0.32v8s 的置信度是 0.58。第二张是两颗骰子边缘紧贴v5s 能分开两个框v8s 偶尔会把它们合并成一个框。第三张是骰子在画面最边缘只露出一半v5s 直接漏检v8s 勉强输出一个低置信度框且类别正确。这几张图让我意识到评测一个检测模型必须同时看指标和实际场景不能只看 mAP。如果你的应用涉及大量边缘截断或密集摆放建议在验证集里专门加上这类样本不然上线后很可能出现指标好看但现场不灵的情况。4. 训练阶段复盘参数、曲线和一次中断事故4.1 两套模型的训练参数配置我分别复现了 v5 和 v8 的训练流程具体参数如下表参数YOLOv5sYOLOv8s输入尺寸640×640640×640训练轮数150150batch size1616优化器SGDAdamW初始学习率0.010.001余弦退火开启开启数据增强Mosaic、HSV 扰动Mosaic、HSV 扰动混合精度开启开启为什么不统一优化器v5 官方配置默认 SGD 加 0.01v8 官方默认 AdamW 加 0.001我尽量保持默认这样测出来的对比更接近多数用户实际使用时的效果。如果你的显存小把 batch 降到 8同时把学习率按比例稍微调低。4.2 训练曲线怎么读训练日志里最值得盯的是 box_loss、cls_loss 和验证集 mAP。对骰子任务来说cls_loss 下降得比 box_loss 慢很多因为六个类别的外观实在太接近。我在 v5 日志里看到前 40 轮 loss 快速下降之后进入平台期v8 在前 20 轮就把 box_loss 压得很低分类损失在 50 轮后仍有缓慢下降说明 v8 后期还在继续打磨分类边界。如果遇到 val_loss 反复波动但 mAP 不涨的情况优先检查验证集标注错误和训练集重复图片不要急着调学习率或增强强度。骰子点数这类任务对旋转增强很敏感随机旋转 180 度后点阵排列会变得不符合常识基线特征容易被破坏。我在训练时把旋转增强角度限制在 0 到 45 度之间实际效果比完全随机旋转更好。4.3 中断恢复时踩过的坑训练到 97 轮时突然遇到显存不足我只能中断。由于保存了 checkpoint我直接用了自带 resume 参数的命令接着训练。理论上没问题但重启后模型 mAP 恢复得很慢十多个轮次都没有超过中断前的最高值。后来查看发现中断后的 batch 顺序被打乱学习率也被恢复逻辑调到了偏高的数值模型产生了明显震荡。处理办法是中断恢复时不直接继续跑从保存的 best 权重加载把学习率手动降到原值的十分之一再重新启动训练 50 轮。这样操作反而比直接 resume 更稳定。这类小项目完全没必要追求一次训到底中途卡住时用最稳的方式恢复比省那几分钟更重要。5. 从模型输出到骰子总点数后处理逻辑实现5.1 单帧检测结果的解析模型输出的原始结果是若干个检测结果每个结果包含类别 id、置信度和边框坐标。首先要按置信度阈值过滤掉低可信目标再做 NMS 去除重复框最后把类别 id 映射成对应点数。类别转点数的函数很简单def to_point(class_id, names): # names: [one, two, three, four, five, six] return names[class_id]如果只需要数字直接输出 class_id 1。这本是个小逻辑但很容易出错。我因为忽略 data.yaml 里的 names 顺序把类别编号直接当点数用测试时所有点数整体偏移一位。强烈建议在后处理代码里显式维护一个类别到点数的映射表方便排查。5.2 视频流中多骰子的跨帧跟踪与点数投票在固定摄像头画面里骰子被检测到之后下一帧还会再出现。如果每一帧都对所有检测结果做点数合计同一个骰子会被重复计算总数会越加越大。我采用了一个轻量级跟踪方案用上一帧与当前帧检测框中心点的距离做最近邻匹配距离小于阈值就认为是同一颗骰子。匹配上之后为每个骰子维护一个点数投票窗口窗口内出现次数最多的类别作为最终点数。这样即使某一帧漏检或误检也不会立刻影响最终统计。核心代码import math def track_and_vote(detections, tracks, max_dist80): updated [] for det in detections: best_i -1 best_d max_dist for i, tr in enumerate(tracks): d math.hypot(det[cx] - tr[cx], det[cy] - tr[cy]) if d best_d: best_d d best_i i if best_i 0: tr tracks[best_i] tr[votes].append(det[point]) if len(tr[votes]) 15: tr[votes].pop(0) tr[point] max(set(tr[votes]), keytr[votes].count) tr[cx], tr[cy], tr[conf] det[cx], det[cy], det[conf] updated.append(tr) else: updated.append({ cx: det[cx], cy: det[cy], point: det[point], votes: [det[point]], conf: det[conf], }) return updated这个方案比调用现成目标跟踪算法简单得多对骰子这类运动幅度小、目标数量少的情况够用。如果桌面有剧烈晃动或频繁遮挡还是建议用带轨迹预测机制的方案。5.3 置信度阈值与NMS的调优细节YOLO 默认置信度阈值通常是 0.25但实测中低光场景下的正确骰子置信度会掉到 0.2 以下用默认阈值会造成漏检。我把阈值调到 0.15漏检明显减少但也带来少量背景误检。为了平衡我会在 NMS 之后额外做一个基于目标尺寸的过滤把面积过小或长宽比严重异常的框丢弃。NMS 的 IoU 阈值同样要调。默认 0.45 在骰子间距正常时没问题但两颗骰子紧贴时过高的 IoU 阈值可能把两个框合并成一个。降到 0.4 之后贴边场景的分离效果好一些。调参没有绝对标准建议做一个小的滑块调试工具边看画面边调比反复改配置重启快得多。6. 部署现场踩坑反光、遮挡、边缘截断6.1 光滑台面反光导致漏检我最早在普通白色桌面上测试效果很理想。后来把骰子放到一块玻璃板上问题立刻来了玻璃反光严重骰子白色圆点在高光区域里几乎看不清模型丢失了很多关键特征6 点骰子经常被漏检成 4 点甚至完全漏掉。解决手段按优先级排序第一换光源把点光源改成漫反射光源或在镜头前加偏振镜消除镜面反射第二收集反光场景下的图片加入训练集让模型见过这类分布第三如果前两点都做不到只能在部署脚本里做多尺度滑动窗口推理尽量覆盖高光区域。我的最终方案是前两者搭配使用反光问题基本消失。6.2 叠放骰子的召回率问题骰子叠放是桌游场景里必然会出现的。两颗骰子叠在一起时部分点数被遮挡模型召回率下降。我统计了测试集里遮挡目标的检测结果当遮挡比例超过一半后漏检率接近 30%。这个数字在真实使用中是不能接受的。改进思路只有一条让训练集出现更多遮挡样本。可以从网上收集自然投掷的骰子图片也可以用程序切出遮挡样本做增强。需要提醒的是程序增强时别让点阵拼接成新的假点数比如 1 点骰子和 4 点骰子叠加后看起来像 3 点。这类样本生成后一定要人工检查。增强后遮挡目标的召回率能提高约 5 个百分点虽然不算质变但已经能压到可用范围。如果应用场景不接受任何漏检就在部署环节加入声光提醒让人工介入摆正骰子。6.3 画面边缘目标被截断固定相机拍摄桌面时画面边缘总会露出来半颗骰子。对这类目标模型普遍输出低置信度甚至直接漏检。处理方式从三方面入手硬件层面把相机位置抬高缩小画面范围保证骰子活动区在画面内部。推理层面在画面四周留出 10% 的安全边界对落在边界外的检测结果做低置信度降权避免边缘误检影响统计。后处理层面把边缘目标的置信度阈值调低并把这部分结果单列出来由后续逻辑决定是否采用。这类坑在算法层面很难完全解决在设计阶段规划好画面布局比在模型层面死磕划算得多。7. 最后建议v5还是v8以及后续扩展方向7.1 如何决定用v5还是v8我的最终选择是固定机位、环境可控的桌面场景用 v5s速度快、模型小多角度拍摄、光照变化明显的场景用 v8s泛化能力和分类稳定性更强。不要被“新版一定更强”这种说法带偏模型选型永远要结合部署目标和算力上限。如果部署在低算力的嵌入式设备上建议进一步把模型导出为 ONNX 格式再用推理加速引擎做量化。量化后模型体积可以压缩一半以上推理速度也能提升两到三倍。量化会带来少量精度下降对骰子点数识别这种类别明确的简单任务影响不明显值得一试。7.2 可以继续扩展的方向这个项目后续还有不少可以玩的空间。一个是接语音播报模块摄像头拍到骰子后直接语音报出总点数桌游场景里很实用。二是接机器人抓取系统让机械臂按骰子类别做分拣需要一个传送带或固定工位配合。三是做手机拍照识别的小程序模型转成移动端格式后在手机端完成推理。做这些扩展时一定要重新评估数据分布。骰子换颜色、换背景、换光源后模型精度都可能下降必须补充对应环境的样本再重新微调。不能指望一个模型通吃所有场景这是我在多次部署里反复验证过的结论。这个项目让我最大的收获不是把 mAP 刷到多高而是理解到在一个看似简单的“小”目标检测任务里数据集质量和场景覆盖比选哪个模型版本重要得多。上面这些教训都是我实打实踩出来的希望能帮你少走一遍弯路。

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

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

免费获取报价 →
↑