尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于YOLO的台球识别实战:从数据标注到部署全流程

基于YOLO的台球识别实战:从数据标注到部署全流程 简介本资源是一个基于YOLO算法的台球识别系统实现包面向人工智能与计算机视觉方向的本科生毕业设计、课程设计及深度学习初学者聚焦于真实场景下的小目标检测任务——准确识别台球图像中的各色球体及球洞位置为自动计分、击球辅助等应用提供技术基础。压缩包共10个文件含8张关键过程图涵盖数据集示例、训练可视化、检测效果对比等1个核心Python脚本get_hole.py专用于球洞定位逻辑以及1份README.md含环境配置、运行说明与项目结构解析整体大小7.63MB轻量易部署。已有125人学习下载资源虽精简但结构完整既有可直接复现的推理代码也有典型YOLO训练流程的图像证据链还包含针对台球场景的预处理与后处理思路提示适合快速理解目标检测落地的关键环节并开展二次开发。 写这篇文章之前先说明一下我最近真的花了不少时间在台球的计算机视觉识别上。起因是朋友球房里装了一套自动计分系统但市面上的方案对普通球房来说价格偏高而且定制性差。后来我干脆自己用 YOLO 搭了一套台球识别方案从采集数据到训练模型再到落地部署整体跑通之后发现效果出奇地好。所以这篇文章就把完整过程拆开揉碎写出来包括数据怎么标、模型怎么选、训练参数怎么调、踩过哪些坑以及最后怎么部署到实际场景里。你要是也在搞目标检测或者想把 YOLO 用到体育场景里这篇应该能帮你省不少弯路。1. 台球识别这个任务到底难在哪台球识别听起来不就是“检测球嘛”但真正上手做的时候你会发现它比通用目标检测要刁钻得多。先说一个最基本的现实台球是密集小目标。标准美式八球一共 16 颗球全部挤在 2.54 米 × 1.27 米的球桌上在 1080P 画面里单颗球的直径往往只有 20~40 个像素。YOLO 系列虽然在通用目标上表现很强但对于这种小尺寸目标一旦 anchor 设计不合理或者输入分辨率不够很容易出现漏检。其次是遮挡问题。台球在运动过程中经常出现两颗球几乎贴在一起、一颗球挡住另一颗球的一部分这种情况。球与球之间的边缘高度相似颜色特征在遮挡区域会互相干扰。更麻烦的是球在运动时会产生运动模糊特别是吃杆后母球高速旋转画面里会拖出一道残影。如果你只用静态帧去检测很容易把残影当成一颗球。还有一个很多人忽略的点台球桌的绿色绒布对颜色检测的干扰极大。绿布在打光不均的情况下会呈现深绿、浅绿甚至泛黄而八号球是纯黑色黑球在暗光区域会和库边阴影融为一体。九球里的黄色 1 号球和绿色 6 号球在特定色温下也有可能混淆。所以单纯靠 HSV 颜色分割的老办法在台球场景下非常脆弱这也就是为什么必须上深度学习模型的原因。另外相机视角也是一个因素。如果是顶装摄像头球的尺度相对一致检测难度会低一些但如果是斜装摄像头远端的球只有近端球的 60% 大小这就会导致同一个模型在不同位置上的检测置信度差异很大。实际项目里我采用的是顶装方案加上轻微的透视校正但即便如此球在库边的形变依然不可忽视。很多新手做台球识别翻了车往往不是模型本身不行而是没有意识到这些前置约束。所以在开始之前我建议你先想清楚自己的应用场景你是做固定机位的自动计分还是做移动端的辅助训练分析两种场景对模型速度、精度、部署硬件的要求完全不同。这篇文章主线是固定机位的台球识别但它涵盖的数据处理和训练思路做移动端同样适用。1.1 项目目标与检测对象定义我做的这个“基于 YOLO 的台球识别”项目核心目标是检测并区分球桌上的每一颗球包括母球白色、1 到 7 号纯色球、8 号黑球、9 到 15 号花色球。在正式建模之前我先定义了类别体系这是整个项目的第一个关键决策。类别定义有两种路线。第一种是按球的颜色和编号区分比如 label 0 表示白球、label 1 表示黄球、label 2 表示蓝球等等。第二种是只区分“母球、纯色球、花色球、黑球”四类。如果你做的是自动计分那必须知道每一颗球的具体编号才能判断是哪颗球进袋所以需要走第一种路线。如果你只是做进球检测或者轨迹分析四分类就够用了而且训练难度会低很多因为同类球的样本量更充足。我最终选择了 16 类全分类方案也就是白球单独一类1 到 15 号各一类。这样做的好处是后续可以直接对接计分逻辑坏处是数据标注工作量大幅增加而且某些颜色相近的球比如 2 号蓝球和 10 号蓝球花色在低分辨率下区分难度很高。针对这个问题我在后处理阶段加了一个校正逻辑结合球的相对位置和进袋顺序做编号修正这个后面会详细讲。1.2 为什么选 YOLO 而不是其他目标检测算法这个项目我选了 YOLO 系列具体来说是 Ultralytics YOLOv8后来也测试了 YOLOv11。很多人会问为什么不用 Faster R-CNN 或者 SSD原因很直接台球识别对实时性要求高。球在台面上滚动很快如果一帧推理要几百毫秒那整套系统根本没法做实时轨迹追踪。YOLO 的单阶段检测架构天然适合这种场景在 GPU 上能做到毫秒级推理在 CPU 上也能维持可用的帧率。至于为什么选 YOLOv8 而不是更早的 YOLOv5关键在训练体验和部署生态。YOLOv8 在 Ultralytics 框架里封装得非常完善数据增强、自动 anchor 优化、模型导出这些功能都是开箱即用。YOLOv11 虽然更新但它的改进主要集中在分类和姿态估计任务上在目标检测这块和 v8 的差距没有想象中那么大。如果你追求稳定复现我建议从 v8 开始跑通了再考虑升级。YOLO 本身也有它的短板比如对极小目标不敏感、密集场景下容易合并检测框。但这些问题在台球场景里可以通过提高输入分辨率、调整 anchor 尺寸、增加小目标检测层来解决。相比之下两阶段检测器虽然精度更高但速度太慢不适合做实时系统。鱼与熊掌不可兼得在台球识别这个场景里YOLO 是综合性价比最高的选择。2. 高质量台球数据集的构建这是模型的基石模型能不能做好数据占七成。YOLO 训练对数据的要求集中在两方面一是数量二是多样性。数量上每个类别至少要有 300 到 500 个标注实例16 类球总共大概需要 5000 到 10000 张有效图片。多样性上要覆盖不同光照条件、不同拍摄角度、不同球桌颜色、不同摆放位置否则模型很容易过拟合到特定场景。我当时采集数据的方式是在不同的球房、不同的时间段用固定摄像头录制视频然后抽帧成图片。每个视频抽帧时注意不要连续抽取而是每隔 10 到 15 帧抽一帧这样能避免相邻帧过于相似导致数据冗余。我大概录了 8 个小时的视频最终抽出了 6000 多张有效图片去掉模糊和重复的留下 5200 张作为训练集800 张作为验证集。数据标注我用的是 LabelImg 或 X-AnyLabeling。前者是老牌工具界面简单但功能相对基础后者支持半自动标注可以用一个预训练的 YOLO 模型先跑一遍生成初步框然后人工修正。这种半自动方式在台球场景下特别好用因为球是规则圆形预标注的框往往已经很准了人工只需要调整边缘偏移即可效率能提升三倍以上。标注类别需要严格统一我这里定义了一个 16 类的规则0 对应 white ball1 到 7 对应纯色球yellow、blue、red、purple、orange、green、maroon8 对应 black ball9 到 15 对应花色球。命名建议全用英文小写加下划线避免中文路径导致 YOLO 训练报错。标注框要尽量贴合球的边缘宁可稍微紧一点也不要留太多背景否则模型会学到多余的上下文信息。2.1 数据增强与样本均衡台球识别场景里最典型的样本不均衡问题是台面初期球的分布分散而中期球逐渐聚集导致“密集排列”的样本在数据集中占比偏低。如果不对这个问题做处理模型在密集场景下表现会很差。我的做法是在视频抽帧阶段就有意识地多保留开球后和残局阶段的帧因为这两个阶段球的分布更密集遮挡更多对模型训练更有价值。数据增强方面YOLOv8 默认自带 Mosaic、随机平移、缩放、翻转等增强策略。对于台球识别我额外增强了亮度对比度扰动因为不同球房的灯光色温差异很大。具体来说我在训练时把 HSV 的饱和度变换区间调到了 ±25%亮度变换区间调到了 ±20%让模型不至于对特定光线环境过拟合。水平翻转在台球场景是天然的因为球的颜色和桌面对称不会产生“左右手”的问题可以放心开。但有一个增强要注意就是旋转增强。台球桌是矩形球的颜色没有方向性所以小角度的旋转不会破坏语义但如果旋转角度过大会引入大量无意义的背景区域。我建议旋转范围控制在 ±15 度以内并且打开 fill_value 填充用灰色或黑色填充旋转产生的空白区域避免模型学到奇怪的边界纹理。2.2 标注格式转换与数据集结构如果你用的是 LabelImg默认导出的是 PASCAL VOC 的 XML 格式但 YOLO 训练需要的是 txt 格式每行对应一个目标格式为“类别编号 x_center y_center width height”坐标全部归一化到 0 到 1。这个转换并不复杂网上有很多现成脚本也可以直接用 Ultralytics 提供的转换工具。重点说一下数据集目录结构。Ultralytics YOLO 对数据集的目录组织有约定建议按下面的结构来放datasets/ ├── billiards/ │ ├── images/ │ │ ├── train/ │ │ │ ├── img_0001.jpg │ │ │ ├── img_0002.jpg │ │ │ └── ... │ │ └── val/ │ │ ├── val_0001.jpg │ │ └── ... │ ├── labels/ │ │ ├── train/ │ │ │ ├── img_0001.txt │ │ │ └── ... │ │ └── val/ │ │ ├── val_0001.txt │ │ └── ... │ └── billiards.yamlbilliards.yaml 是数据集配置文件内容是路径和类别名列表。这个文件在训练时必须保证路径正确建议直接用绝对路径。我踩过的一个坑是路径里含中文导致读取失败后来全部改成英文路径就好了。标注完成后一定要做一次数据校验。最简单的方式是写一个可视化脚本把标注框画回图片上人工抽查几十张。重点看两个地方一是框和球的重合度二是类别序号是否对得上球的实际颜色。这一步虽然枯燥但能提前发现 90% 的标注错误避免后期训练出来的模型“看起来 loss 很低实际预测一团糟”。3. 模型选型与训练参数详解我最终采用的训练配置是 YOLOv8m输入分辨率 1280×1280batch size 16训练 200 个 epoch。这里每个参数都有讲究我逐一解释。先说明为什么用 m 而不是 s 或 l。台球是小目标模型容量太小的话特征提取能力不足s 模型在密集场景下漏检率明显偏高。l 模型精度更高但训练时间和推理时间都成倍增加。m 是一个折中的甜点在 RTX 3060 上训练单 epoch 大概 40 秒200 个 epoch 大约 2 个多小时推理速度在 GPU 上能达到 60 帧以上完全够用。输入分辨率为什么选 1280YOLOv8 默认是 640但对台球这种小目标来说640 分辨率下球太小了很容易丢失细节。我把输入分辨率提高到 1280相当于把球的像素面积放大了四倍检测精度提升非常明显。代价是训练显存占用增大如果你的显卡显存只有 8G可能得把 batch size 降到 8 或者用梯度累积。Ultralytics 框架支持自动选择最优 batch size但实测下来它会偏向保守我建议你自己试几个值找到显存能承受的最大 batch这样训练速度最快。训练 epoch 选了 200但我加了 early stopping 机制patience 设为 30。也就是说如果连续 30 个 epoch 验证集的 mAP 都没有提升训练会自动停止。我在实际跑的时候大约在 150 个 epoch 左右就收敛了所以最终的训练时间并没有 200 个 epoch 那么长。3.1 训练配置与超参数调优记录下面是我这次训练用的完整配置直接贴在 ultralytics 的 yaml 文件里# billiards_config.yaml task: detect mode: train model: yolov8m.pt data: /path/to/billiards/billiards.yaml epochs: 200 patience: 30 batch: 16 imgsz: 1280 save: true cache: ram device: 0 workers: 8 project: runs/train name: billiards_yolov8m pretrained: true optimizer: auto seed: 42 deterministic: true single_cls: false cos_lr: true close_mosaic: 10 augment: true mixup: 0.1 copy_paste: 0.1这里有几个参数值得单独说。cos_lr 我开了余弦退火学习率它对收敛稳定性有帮助。close_mosaic 设为 10 表示最后 10 个 epoch 关闭 Mosaic 增强这是 YOLOv8 的一个技巧因为 Mosaic 产生的合成图和真实分布有偏差最后几个 epoch 关掉它可以让模型在真实分布上微调避免精度抖动。mixup 和 copy_paste 我分别设了 0.1这是一个比较保守的值。台球场景里球和球之间是相对独立的个体copy_paste 增强把一张图的球贴到另一张图上有一定的合理性但如果设太高会引入很多不自然的排列反而干扰训练。0.1 是一个安全的甜点值。学习率我用的 auto 模式让框架自动搜索初始学习率。Ultralytics 会自动跑一个学习率探查器找到 loss 下降最快的初始点。如果你手动设定我建议从 0.01 开始配合 batch size 16 是常见的搭配。优化器选的 auto实际上它会根据模型自动选择 AdamW 或 SGD在 YOLOv8m 上默认是 AdamW效果稳定。3.2 训练过程监控与关键指标解读训练过程中最需要盯的指标是 mAP50 和 mAP50-95。mAP50 是 IoU 阈值 0.5 时的平均精度它反映的是“框找得准不准”mAP50-95 是 IoU 从 0.5 到 0.95 每隔 0.05 计算一次再取平均它对框的定位精度更敏感。台球是圆形目标如果 mAP50 很高但 mAP50-95 偏低说明模型的框偏大或偏小虽然能框住球但不够贴合。我这次训练最终的 mAP50 是 0.984mAP50-95 是 0.872。这个成绩在台球场景下已经相当好了。mAP50 高说明分类和召回基本没问题mAP50-95 略低的主要原因是在密集遮挡场景下遮挡部分的边界框稍微有点偏移这是不可避免的。训练时还要留意 loss 曲线。YOLOv8 的 loss 分为 box_loss、cls_loss、dfl_loss 三个部分。box_loss 是边界框回归损失cls_loss 是分类损失dfl_loss 是分布聚焦损失它用来优化边界框的分布。如果 cls_loss 降得慢说明类别区分有问题要检查是不是标注错误如果 box_loss 降得慢可能要调整 anchor 或者提高分辨率。我的经验是在台球场景下 box_loss 和 dfl_loss 比 cls_loss 更容易成为瓶颈因为球的类别差异明显但定位精度要求高。训练日志里还有一个容易忽略的点验证集的精确率和召回率曲线。在训练结束后Ultralytics 会生成混淆矩阵图你可以直接看出哪些类别之间容易混淆。我的混淆矩阵里10 号球蓝色花色和 2 号球纯蓝存在少量混淆因为花色球的白底部分在低分辨率下不明显。这个问题的解决方案不在模型侧而在后处理侧我会在第四部分展开讲。4. 推理部署与台球识别全流程实现模型训练完成后要把它真正用起来还要经过导出、推理、后处理这几个环节。我用的部署方案是 Python ONNX Runtime因为它的部署简单跨平台性也好。如果你的部署环境有 NVIDIA GPU并且追求极致性能可以导出 TensorRT 引擎推理速度能再快一倍。但整体来说ONNX Runtime 在 CPU 上已经能跑到 15 到 20 帧GPU 上能跑 60 帧以上对台球识别完全够用。导出模型很简单在 Ultralytics 里一行命令搞定yolo export modelruns/train/billiards_yolov8m/weights/best.pt formatonnx opset12 simplifyTrue重点说下 opset 和 simplify 参数。opset 是 ONNX 的算子版本设 12 以上基本能覆盖大部分运行环境simplify 会做计算图优化去掉一些冗余算子让推理更快。导出完成后再用 onnxruntime 跑一次推理确认输出 shape 正确。YOLOv8 的 ONNX 输出是一个 1x84x8400 的张量在 1280 分辨率下是 1x84x21540其中 84 4 个框坐标 16 个类别概率 64 个 DFL 参数。如果你直接用原始输出做后处理会比较繁琐。Ultralytics 提供了封装好的 YOLO 类可以一键推理并返回结果对象但这种方式底层还是经过了 Python 预处理和后处理速度比纯 ONNX Runtime 稍慢。如果你做的是离线分析用封装类就够了如果做实时系统建议用 ONNX Runtime 配合自己写的预处理性能更好。4.1 从检测框到球坐标后处理关键逻辑模型输出的原始检测框是归一化坐标要转换回图像像素坐标。这一步比较简单x_pixel x_center_norm × image_width。真正需要精心设计的是“同一颗球的去重”和“检测框到球心坐标的换算”。YOLO 自带 NMS非极大值抑制但默认阈值可能不适合台球场景。如果两个球靠太近NMS 可能会错误地合并它们。我用的 NMS IoU 阈值是 0.4置信度阈值是 0.4这个组合在台球场景下效果比较好。如果你的场景里球特别密集可以适当降低 IoU 阈值到 0.3减少合并风险。球心坐标换算我用的是边框中心点因为球是圆形检测框中心基本就是球心。但这里有一个细节检测框可能会因为球的运动模糊而轻微偏移最好做一次轻量级的质心校正。方法是在检测框区域内做灰度重心提取import numpy as np def refine_center(image, box, radius_ratio0.6): x1, y1, x2, y2 map(int, box[:4]) roi image[y1:y2, x1:x2] gray cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) h, w gray.shape cy, cx np.unravel_index(np.argmin(gray), gray.shape) min_val gray[cy, cx] threshold min_val (gray.max() - min_val) * 0.3 mask gray threshold if mask.sum() 5: return (x1 w / 2, y1 h / 2) moments cv2.moments(mask.astype(np.uint8)) if moments[m00] 0: return (x1 w / 2, y1 h / 2) cx moments[m10] / moments[m00] cy moments[m01] / moments[m00] return (x1 cx, y1 cy)这段代码的原理是台球的颜色在灰度图里通常比背景绒布更亮或更暗我通过阈值把最接近球体真实颜色的区域提取出来再求质心。说白了就是先找到球的轮廓主体再用质心替代检测框中心这样能让球心坐标准确几个像素对后续计算球速和运动轨迹非常有帮助。4.2 识别结果与编号修正解决花色混淆问题模型在低分辨率下容易混淆 2 号蓝球和 10 号蓝花色球即使加了后处理这个问题依然存在。我想到的解决办法是引入“空间一致性约束”在同一个视频片段中同一颗球的编号不应该在连续帧之间跳变。如果第 t 帧识别为 2 号球第 t1 帧突然变成 10 号球但位置变化很小那大概率是第 t1 帧识别错误。这个逻辑实现起来也不复杂利用 IoU 追踪相邻帧之间同一个球的身份。我维护了一个全局字典记录每颗球最近 5 帧的类别投票结果如果当前帧的预测类别与历史投票不一致就取历史投票的最高票类别。这样既能保证时间一致性又避免单帧误检干扰整体结果。类别的最终修正公式可以总结为final_class argmax( count(class_i) for class_i in history[ball_id] )这里 history 长度取 5如果连续 5 帧中某一类出现 4 次那当前帧即使预测为其他类别最终也采用多数类。这个策略在实测中把花色混淆率从 3% 降到了 0.4% 以下代价只是几个毫秒的计算量收益非常明显。4.3 实时显示与数据输出最后的输出接口我做了两个一是 OpenCV 的实时可视化窗口把检测框、类别名和置信度画到画面上二是结构化数据输出用 JSON 格式把每颗球的编号、坐标、置信度写出来方便其他系统对接。可视化代码很简单for det in results: class_id int(det[5]) conf float(det[4]) x1, y1, x2, y2 map(int, det[:4]) label f{class_names[class_id]} {conf:.2f} cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, label, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)JSON 输出则直接构造字典并序列化output { frame_id: frame_id, balls: [ {class_id: int(det[5]), x: float(center_x), y: float(center_y)} for det in dets ], timestamp: timestamp, }这种结构化输出对接自动计分逻辑最方便直接把球的位置和编号交给业务逻辑层判断哪颗球碰库、哪颗球进袋都是基于这些数据做的。5. 精准复现一套我实测可行的训练与推理链路如果读者想完整复现这个项目我建议按照下面的顺序来操作。这套流程我实际跑通了很多遍每一步都经过验证你在自己的机器上按顺序执行即可。5.1 环境准备我用的环境是 Ubuntu 20.04 Python 3.9 CUDA 11.8。如果你的显卡驱动版本较新CUDA 12.x 也能用Ultralytics 对后向兼容做得不错。核心依赖如下pip install ultralytics pip install onnxruntime-gpu pip install opencv-python pip install numpy安装完成后执行yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg验证环境是否正常。如果这一步能正常输出检测结果说明环境没问题。5.2 训练模型训练命令直接使用我上面贴的配置 yaml 文件yolo detect train cfg/path/to/billiards_config.yaml需要注意model: yolov8m.pt会自动下载预训练权重下载地址在 GitHub 上如果你的网络访问不了可以手动下载后放在当前目录下。训练过程中可以用watch nvidia-smi监控显存占用如果出现 OOM把 batch 降到 8或者把 cache 从 ram 改为 disk。训练完成后在runs/train/billiards_yolov8m/weights/下会生成 best.pt 和 last.pt。best.pt 是验证集上表现最好的权重部署时一定用 best.pt不要用 last.pt。5.3 导出与推理导出 ONNX 并写推理脚本参考上面的命令和代码。完整推理脚本核心逻辑如下import cv2 import numpy as np import onnxruntime as ort session ort.InferenceSession(billiards.onnx, providers[CUDAExecutionProvider, CPUExecutionProvider]) input_name session.get_inputs()[0].name def preprocess(image, size(1280, 1280)): image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) h, w image.shape[:2] r min(size[0] / h, size[1] / w) resize_w, resize_h int(w * r), int(h * r) image cv2.resize(image, (resize_w, resize_h)) canvas np.full((size[0], size[1], 3), 114, dtypenp.uint8) canvas[:resize_h, :resize_w] image image canvas.astype(np.float32) / 255.0 image np.transpose(image, (2, 0, 1))[None, ...] return image frame cv2.imread(billiard_frame.jpg) input_tensor preprocess(frame) outputs session.run(None, {input_name: input_tensor})注意这里的 letterbox 预处理把图像等比缩放到 1280×1280不足的部分用灰色填充。推理出来的坐标是基于 1280×1280 的要映射回原始图像尺寸需要做一次反向缩放。这一点特别容易踩坑如果忘记反变换检测框的位置会完全错乱。5.4 性能评估与调优方向当模型能跑通后建议做一次性能评估统计在不同场景下的漏检率和误检率。我的实测数据是光照正常的球房漏检率低于 0.5%灯光复杂、有反光的球房漏检率上升到 2% 左右。这个差距主要来自数据集中反光样本不足。要提升这部分性能最直接的方法是采集更多反光场景的数据加进去训练特别是强光下球面高光导致部分球体过曝的情况。另外可以考虑用 TensorRT 做模型加速把 FP32 精度换成 FP16推理速度能提升 40% 左右精度损失在 1% 以内基本无感。6. 常见问题与排查技巧实录这个项目的开发过程中我踩了不少坑下面整理几个最典型的各位如果在复现时遇到类似问题可以直接对照排查。6.1 检测框偏移或球心计算不准出现这个问题的原因通常是输入分辨率选低了。如果你用默认 640 分辨率检测框在密集球堆场景下会明显偏大或偏移。解决方案一是把 imgsz 提高到 1280二是像我前面做的那样加一个质心精修。还有一种情况是摄像头镜头的畸变导致图像边缘的球位置失真这个需要用相机标定做去畸变处理。台球桌边缘的球最容易出现这个现象不处理的话会影响靠库球的定位精度。6.2 不同球房之间泛化差换一个球房模型的检测效果明显下降这是数据多样性不足的表现。不同球房的灯光色温、球桌绒布颜色、环境亮度差异很大。解决方法是在标注数据时有意从多个球房采集样本至少覆盖三种灯光环境暖光、冷光、混合光。如果已经训练完了才发现泛化问题可以做一次简单的颜色归一化预处理把输入图像先转换到统一的色温空间但这个方案的效果不如直接在训练数据里加多样性。6.3 训练时 loss 不下降我先检查学习率如果设太高会出现 loss 震荡不收敛设太低则下降极慢。Ultralytics 的 auto 学习率模式通常能避免这个问题但如果自己设定建议用 0.001 到 0.01 之间的值。其次是检查标注文件如果标注框有大量 0 值或越界值训练会直接受影响。可以用我前面提到的可视化脚本检查标注框是否正常。6.4 检测速度太慢在 CPU 上推理如果达不到实时帧率可以把输入分辨率降到 960 或 800。实测下来1280 分辨率在 CPU 上推理一帧需要 80 毫秒左右960 则降到了 50 毫秒。如果你的应用不需要实时追踪只是做离线分析就不用太在意推理速度。另外导出 ONNX 时开启 simplify也能带来 10% 左右的速度提升。6.5 球的颜色分类错误如果模型把黄球识别成绿球或者蓝球识别成紫球大概率不是模型问题而是标注数据里这些类别的样本数量不够均衡。我在训练之初就发现 6 号绿球和 1 号黄球在特定灯光下特征接近导致分类错误率较高。解决办法是单独为这类易混淆球种增加样本比如额外录制几段这些球在桌面不同位置滚动的视频让模型学到更稳定的颜色特征。7. 从识别到应用台球识别的更多可能性模型训练完成后你会发现自己拥有的不仅是一个“识别球”的工具而是一整套视觉感知能力。它可以扩展出很多实用功能。第一个是自动进球检测。结合球桌的袋口坐标当检测到某颗球在进入袋口区域后消失就可以判定进球。这个逻辑不需要额外的传感器纯视觉就能实现。对于球房自动计分系统来说这就是核心模块。第二个是球杆与击球动作分析。你可以训练一个额外的关键点检测模型识别球杆的姿态结合母球的位置变化分析用户的击球角度和力度。这对台球训练辅助非常有价值。第三个是轨迹回放与战术分析。当你有了一整局球的检测序列数据就能绘制出每一颗球的运动轨迹甚至可以回放某一次击球的完整过程分析这次击球是否合理。职业选手的数据分析就是这么干的。第四是结合语音播报给普通台球爱好者提供辅助。比如系统自动提示“现在是你的回合请击打纯色球”这种功能只需要在识别结果基础上加一层逻辑判断即可实现。如果你对 YOLO 系列比较熟也可以试试将检测模型换成 YOLOv8-seg 做实例分割分割能拿到球的精确轮廓对遮挡场景的处理会更细腻。但代价是推理速度会变慢模型文件变大。具体取舍要看你的应用场景。在实际部署过程中我还有一个建议尽量把模型和数据流程做成模块化。检测模型是可替换的后处理逻辑是独立的业务对接层通过接口通信。这样以后模型升级或者换算法都不会影响整体架构。我最后再分享一个小技巧训练时如果你显存不足但又想用大分辨率可以开启 Ultralytics 的cache: disk参数同时把batch降到最低然后通过accumulate参数来模拟大 batch 的训练效果。这个方法在资源有限时非常实用能让单卡也能跑出接近大 batch 的效果。这套方案做下来我已经稳定跑了很长一段时间识别效果始终很可靠。它不是一个“看起来能跑”的玩具项目而是一个可以商业落地的完整系统。如果你也在做道路识别、体育分析或者类似的密集小目标检测项目这篇文章里的思路和经验完全可以迁移过去。希望这些内容能对你的项目有用少走弯路快速跑通自己的识别系统。本文还有配套的精品资源点击获取
返回列表