十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MaixCam2部署YOLO11实现60FPS小球检测全流程解析

MaixCam2部署YOLO11实现60FPS小球检测全流程解析 小球高速运动、硬件算力有限、帧率要求还很高——这种组合在竞赛中并不少见。之前在做这套基于 MaixCam2 与 YOLO11 的小球检测方案时最直观的感受是模型不能只看精度还要看“能不能在嵌入式设备上跑得动、跑得稳”。最终方案在题目要求的各类测试场景里都拿到满分表现整体检测能稳定跑到 60 FPS这里把整个项目从思路、训练、部署到性能优化完整复盘一遍适合准备嵌入式视觉竞赛的选手也适合第一次在 MaixCam2 上部署 YOLO11 的开发者参考。1. 项目背景小球检测凭什么要 60FPS先想清楚题目为什么难。小球检测和普通的目标检测不同它是一个“强实时”任务。小球在画面里运动速度快如果检测帧率只有 10~20 FPS那么连续两帧之间小球可能已经移动了一大段距离位置输出会产生明显的台阶感。在一些竞赛题中不仅要求检测到小球还需要根据连续帧位置估算速度、轨迹甚至判断是否会进入某个区域。帧率一旦不够后续的预测逻辑全部会失真。正因如此题目往往要求系统达到 30FPS 以上如果能稳定到 60FPS说明从采集到推理再到输出的整个链路都非常健康。MaixCam2 相比通用开发板的特点是体积小、功耗低、集成度高能直接在设备上进行摄像头采集、推理和显示输出很适合这类“桌面级 动态目标 实时反馈”的场景。但低功耗也意味着算力有限在 PC 上轻松跑 YOLO11m 的显卡环境在 MaixCam2 上并不存在所以模型选择和优化策略会明显影响最终效果。YOLO11 是 Ultralytics 推出的新一代目标检测模型。和 YOLOv8 相比它继续采用 anchor-free 检测头同时对网络模块做了调整整体参数更少、推理延迟更低。YOLO11 的 n/s/m/l/x 多种规格意味着我们可以从最小模型开始评估端侧性能而不是上来就背一个复杂模型。整体来看这个项目要解决的并不是“能不能检测到小球”而是在低算力设备上能不能稳定跑到 60FPS小球比较小、运动快能不能维持低漏检率连续帧检测结果能不能作为后续轨迹预测的可靠输入。围绕这三个问题后面所有方案设计都会有方向。2. 系统方案设计从摄像头到小球坐标动手写代码之前先把整个系统拆成五段链路摄像头采集 ↓ 图像预处理缩放、格式转换、ROI 裁剪 ↓ 模型推理YOLO11 检测小球 ↓ 后处理阈值过滤、NMS、坐标映射 ↓ 输出小球中心坐标 / 是否在区域内 / 帧率统计链路越短延迟越低但每一步都有优化空间后面会逐个拆开。这套思路不只适用于竞赛普通边缘视觉项目也可以复用。技术选型上我建议用下面这个组合模块方案说明硬件平台MaixCam2 或同系列设备需确认摄像头接口与有效像素模型YOLO11n为了端侧帧率优先从最小模型起步训练环境PyTorch Ultralytics先在 PC 上完成数据训练与评测部署方式导出 ONNX 后转端侧推理模型直接用 PyTorch 模型在设备上跑不现实运行语言MaixPy / 官方 SDK具体版本以设备固件为准输出接口屏幕绘制 串口/日志输出方便比赛现场观察与调试项目目录建议按这种结构组织ball_detect/ ├── datasets/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ └── labels/ │ ├── train/ │ └── val/ ├── runs/ │ └── detect/ │ └── train/ # 训练结果会生成在这里 ├── export/ │ └── best.onnx ├── deploy/ │ └── main.py # MaixCam2 端运行代码 └── ball.yaml # YOLO 数据配置这里特别注意YOLO 训练数据和端侧部署代码要分开管理。训练依赖 PC 环境部署代码则要尽量精简不要包含任何 torch 逻辑。3. 环境准备训练侧与部署侧分开看待3.1 PC 端训练环境YOLO11 的训练依旧建议在 PC 上完成因为 GPU 加速能大大缩短迭代时间。环境版本不必死记硬背按下面思路来操作系统Windows 10/11 或 Ubuntu 20.04/22.04 均可Python3.8 以上建议 3.10 或 3.11PyTorch根据显卡驱动安装支持 CUDA 的电脑建议直接安装 GPU 版Ultralytics使用最新稳定版本即可标注工具LabelImg / X-AnyLabeling / Roboflow 都可以输出为 YOLO txt 格式。如果你电脑刚好是 CUDA 12.4 环境安装 PyTorch 时要注意版本匹配。可以先去 PyTorch 官网找到对应 CUDA 12.4 的安装命令核心是保证torch.cuda.is_available()返回 True。安装 Ultralytics 很简单pip install ultralytics安装完成后可以直接验证import ultralytics print(ultralytics.__version__)3.2 部署端环境MaixCam2 端不需要安装 PyTorch而是通过 MaixPy 或其他官方推理框架运行。不同固件版本之间 API 可能差异较大项目中最稳妥的方式是先烧录最新官方固件运行官方摄像头示例确认摄像头和屏幕正常再运行官方神经网络示例确认推理框架能调用最后再把我们自己的 YOLO11 模型接入。部署环境的具体版本要以设备实际支持为准不建议照搬某一篇文章的固定版本。这样做的好处是如果发现帧率、精度有问题你能快速判断是模型问题还是框架问题而不是在混乱的环境里来回猜。4. YOLO11 网络结构认知为什么它适合端侧小球检测YOLO11 延续了 YOLO 系列“Backbone Neck Head”的整体设计Backbone 负责提取图像特征YOLO11 用到了类似 C3k2 的结构比原来的 C3/C2f 模块更关注计算效率Neck 采用多尺度特征融合让不同尺寸的目标都能得到合适的高层语义特征Head 是 anchor-free 检测头直接预测目标中心点到四条边的距离配合 DFL 损失让回归更平滑。整体来看YOLO11 相比 YOLOv8 更强调“精度不下降、速度还能更快”。对小球检测来说有几个点很关键4.1 Anchor-Free 设计降低后处理复杂度早期 YOLO 版本需要预设 anchor部署时要处理数量很多的候选框。YOLO11 的 anchor-free 设计把检测头输出直接理解为每个位置的目标概率和边框偏移NMS 阶段的候选框数量更可控这对端侧 CPU/NPU 推理非常友好。4.2 多尺度检测天然覆盖小目标YOLO11 会在多个尺度的特征图上做预测小目标主要靠较浅层的大分辨率特征图召回。小球在画面中像素可能只有十几个甚至几个像素因此训练时不要盲目压缩输入分辨率需要在小目标和帧率之间找平衡。4.3 轻量化版本更适合嵌入式YOLO11n 是整个系列里参数量最小的版本。实际测试下来在小球这种“目标类别单一、背景可控”的场景中完全不需要追求大模型。与其换用更大的 m/l 模型不如把输入分辨率、训练数据质量、后处理策略做好效果反而更容易达到满分标准。强烈建议训练前先理解这一点在嵌入式视觉竞赛中模型本身的精度差异通常不是决定生死的因素能不能稳定跑在 60FPS 并把小球中心坐标输出准确才是关键。5. 训练自己的小球检测模型5.1 数据采集与标注小球检测任务的数据采集比普通目标检测更讲究多样性。常见问题是训练时只拍同一光照、同一背景的小球到了比赛现场场景变化后漏检率立刻上升。建议至少覆盖以下因素不同光照顺光、逆光、侧光、室内灯光明暗差异不同背景白墙、桌面、地面、复杂背景不同颜色如果题目中会出现多种颜色小球最好都采集不同大小让小球在画面不同距离出现不同运动状态静止、低速、高速、弹跳瞬间。标注时只标一个类别ball即可用 YOLO 格式保存。5.2 准备数据集目录YOLO11 使用 txt 标注文件每行格式是class_id center_x center_y width height坐标值需要归一化到 0~1 之间。目录结构如下datasets/ ├── images/ │ ├── train/ │ │ ├── 001.jpg │ │ └── ... │ └── val/ │ ├── 101.jpg │ └── ... └── labels/ ├── train/ │ ├── 001.txt │ └── ... └── val/ ├── 101.txt └── ...5.3 编写数据配置文件在项目根目录新建ball.yaml# 文件路径ball.yaml path: ./datasets train: images/train val: images/val nc: 1 names: 0: ball其中path路径不要写绝对路径避免换电脑或换环境后失效。5.4 开始训练训练前先用官方预训练权重yolo11n.pt做迁移学习能大幅减少数据需求量。yolo detect train \ databall.yaml \ modelyolo11n.pt \ epochs100 \ imgsz320 \ batch16 \ device0 \ projectruns \ nametrain_ball参数说明epochs100小球类别单一100 轮足够多了反而可能过拟合imgsz320考虑到 MaixCam2 端侧推理建议训练时就用 320 分辨率避免训练与部署分辨率差异过大batch16根据显存调整显存不足可降到 8 或 4device0使用第一张 GPU没有 GPU 可去掉或改成devicecpu。训练结束后结果会保存在runs/train_ball/目录重点看这几个文件weights/best.pt验证集上效果最好的权重部署时用这个results.pngloss、mAP 曲线confusion_matrix.png混淆矩阵帮助我们确认是否存在严重误检。5.5 评估与测试训练完成后的评估不能只看 mAP还要专门用一段“现场模拟视频”测试连续帧稳定性。普通目标检测任务单帧 mAP 高就够了但小球检测项目必须看连续结果判断是否出现漏掉某一帧或者框剧烈抖动。跑一段测试数据from ultralytics import YOLO # 加载最佳权重 model YOLO(runs/train_ball/weights/best.pt) # 对图片推理 results model.predict( sourcetest_images/, imgsz320, conf0.6, iou0.45, saveTrue, )如果训练集球体较小可以调参增强from ultralytics import YOLO model YOLO(yolo11n.pt) model.train( databall.yaml, epochs150, imgsz320, augmentTrue, hsv_h0.02, hsv_s0.5, hsv_v0.3, fliplr0.5, )需要提醒的是小球检测场景往往不需要过度数据增强尤其是颜色通道的大幅扰动可能会让模型对球体颜色产生错误认知建议先用默认增强策略再根据验证集表现逐步调整。6. 从 PyTorch 到 MaixCam2模型导出与部署6.1 为什么不能直接跑 PyTorch 权重YOLO11 的.pt文件是 PyTorch 权重里面同时包含网络结构和训练组件直接放到嵌入式设备不现实。常规做法是先导出为 ONNX再通过官方工具转换成端侧推理格式。以导出 ONNX 为例from ultralytics import YOLO model YOLO(runs/train_ball/weights/best.pt) model.export( formatonnx, imgsz320, opset12, simplifyTrue, )运行完后在runs/train_ball/weights/下会生成best.onnx。这个 ONNX 包含了完整的检测网络结构但还要继续做格式转换和可能的量化压缩。不同 MaixCam2 固件版本对模型格式支持不完全一致通常可以使用 MaixHub 在线转换也可以使用本地工具链把 ONNX 进一步转换为设备推理文件。转换时需要注意输入尺寸必须与训练一致比如 1x3x320x320输出层可能需要额外解析YOLO11 的 ONNX 输出是多个特征层后处理需要知道每个输出对应的 stride如果不做量化模型文件会偏大加载时间也会更长。6.2 在 MaixCam2 上用 MaixPy 跑检测下面代码是 MaixPy 风格的流程骨架具体类名、参数在不同固件下可能略有差异拿到真实设备后要先跑官方示例再替换# 文件路径deploy/main.py from maix import app, camera, display, nn, image # 1. 加载模型 detector nn.YOLO11( model/root/models/ball.mud, input_size(320, 320), conf_th0.55, iou_th0.45, ) # 2. 初始化摄像头与屏幕 cam camera.Camera(320, 320) disp display.Display() while not app.need_exit(): # 3. 采集一帧 img cam.read() # 4. 执行检测 objs detector.detect(img) # 5. 绘制结果并输出坐标 for obj in objs: img.draw_rect(obj.x, obj.y, obj.w, obj.h, color(255, 0, 0)) img.draw_string(obj.x, obj.y, fball {obj.score:.2f}, color(255, 0, 0)) # 输出小球中心 cx obj.x obj.w / 2 cy obj.y obj.h / 2 print(fball center: ({cx:.1f}, {cy:.1f}), score: {obj.score:.2f}) # 6. 显示画面 disp.show(img)这段代码已经接近最终比赛功能实时画面、检测框、置信度、中心坐标输出全部包含。如果题目还需要发送坐标到其他模块只需把print换成串口写入或写变量即可。7. 60FPS 性能优化实战让帧率稳定下来很多同学会遇到一个尴尬情况模型训练完了检测也准但设备上只有 20FPS。下面几个手段是我在实际优化过程中验证过比较有效的方向。7.1 优先检查输入分辨率输入分辨率对帧率影响最大。320x320 比 640x640 的计算量减少约 75%。如果题目中只要求检测小球位置不建议一开始就用 640。思路是先用 320 跑通全流程观察检测效果若小球太模糊再逐步提回到 384 或 416。7.2 设置 ROI 区域裁剪如果小球只在画面某一块区域运动可以先裁剪出 ROI 再送入模型。假设小球运动区域是画面右下部分那么可以先裁剪原图再缩放至模型输入大小# 流程示意ROI 坐标根据实际画面调整 roi_img img.crop(roi_x, roi_y, roi_w, roi_h) input_img roi_img.resize(320, 320) objs detector.detect(input_img) for obj in objs: # 映射回原图坐标 real_x roi_x obj.x * (roi_w / 320) real_y roi_y obj.y * (roi_h / 320)ROI 裁剪相当于把更多像素资源集中在目标上不仅能提升小球检测精度还能降低模型在全图上的搜索范围帧率往往会有可见提升。7.3 模型量化和轻量化在转换端侧模型时建议优先选择 INT8 或 FP16 量化。量化的核心价值是减少模型体积并加速推理但也会导致一点精度损失。正确做法是先不做量化跑通再量化对比验证集精度如果相差很小就果断用量化模型。实际比赛里模型只检测一类小球类别数nc1检测头输出也比 COCO 80 类小很多本身就属于“轻量化友好型”任务量化损失通常完全可接受。7.4 控制 NMS 阈值和输出框数量检测到多个候选框时NMS 会消耗时间。如果画面中通常只有一颗小球那不需要保留大量候选框。可以通过设置更高的conf_th提前过滤低置信度框减少后续 NMS 压力。一个小经验把小球的置信度阈值从 0.25 提到 0.6 甚至 0.7FPS 提升可能不明显但现场误检率会明显下降。因为比赛得分点往往不只是“能测到”还要“不误报”。7.5 减少图像拷贝与显示开销端侧代码里最容易出现的问题是每帧多次复制图像。比如从摄像头拿到图像后又为了画框复制了一次再为了显示复制一次这些都会吃掉帧率。建议摄像头图像 → 推理 → 画框 → 显示都尽量在原图对象上完成或者使用内存复用。显示刷新频率也可以和检测频率解耦比如检测 60FPS显示 30FPS这一般不影响最终成绩。7.6 使用双缓冲和帧统计为了让帧率稳定可以把摄像头采集和检测显示放成两个逻辑或者至少每次循环只读取最新帧不排队等待。端侧摄像头如果采集速度大于推理速度读取旧帧会白白增加延迟。在代码里加入如下统计逻辑能直观看到优化效果import time frame_count 0 start_time time.time() while not app.need_exit(): img cam.read() objs detector.detect(img) frame_count 1 if frame_count 60: elapsed time.time() - start_time fps frame_count / elapsed print(fFPS: {fps:.1f}) frame_count 0 start_time time.time()7.7 优化优先级总结当你发现帧率不达标时按照这个顺序检查输入分辨率是否过高是否可以在画面上做 ROI 限制是否已经使用量化模型每一帧是否存在无意义的图像复制后处理是否过滤了大量低置信度框摄像头是不是工作在了过高的分辨率下这六步走完帧率通常会有 1.5 到 3 倍的提升空间。8. 连续帧稳定输出满分项目的几个细节既然题目中的多个问题都能拿满分说明不仅单帧检测准确率高连续输出也足够稳定。这里分享几个容易被忽略的细节。8.1 小球中心坐标要用浮点数输出很多同学画框没问题但输出坐标时把小数截断成了整数。如果后续还要做速度计算或轨迹判断0.5 像素级别的误差在高速小球场景里会被放大。建议输出浮点坐标并且统一坐标原点。8.2 避免画框抖动影响视觉判断检测框如果每帧边界波动很大人眼看起来会觉得系统不稳定。如果题目不要求框完全贴合小球可以在后处理中增加轻量平滑比如对中心坐标做一阶低通滤波# 简单平滑示例 alpha 0.6 # 0~1越大越相信当前帧 smooth_x alpha * current_x (1 - alpha) * last_x smooth_y alpha * current_y (1 - alpha) * last_y但需要注意平滑会增加“滞后感”如果小球运动过快平滑系数不能太大否则轨迹会明显落后。8.3 做一份连续视频测试比赛现场不能只验证单张图片最好录制一段 10 到 20 秒的小球运动视频离线跑完整个检测逻辑统计总帧数有小球但未检出的帧数误检成小球的目标数中心坐标输出是否出现跳变。只要漏检帧和误检帧都接近 0且帧率稳定说明系统具备满分潜力。8.4 多环境预演如果是现场比试比赛场地光照和训练场地大概率不同。建议训练数据里多混合几种环境或者在赛前准备一个快速微调方案比如现场采集 50 张图片、训练 20 轮做适配。这能让模型对新环境的适应能力大幅提升。9. 常见问题与排查思路下面整理了几个最容易遇到的问题按排查顺序放在一起问题现象常见原因解决思路帧率只有 10~20 FPS输入分辨率太高 / 未量化降到 320、启用量化、设置 ROI检测不到小球训练数据与现场差异太大增加现场图片重新训练或微调频繁误检背景为小球置信度阈值过低 / 背景单一过拟合提高 conf_th增加背景负样本画面上框在抖NMS 阈值不稳定 / 模型对微小特征敏感适当调高 conf考虑坐标平滑ONNX 转换报错opset 版本过高或过低改用 opset 12保留简化导出设备加载模型卡死模型太大 / 格式不匹配使用量化模型确认转换后的尺寸、格式每帧检测结果延时高摄像头缓存旧帧读取最新帧避免队列堆积小球高速运动时中间断裂球在帧间位移过大提高帧率优先项或对运动区域裁剪放大如果你遇到的是“训练时 mAP 不低但设备上漏检特别多”的情况大概率就不是模型问题而是输入分辨率、图像预处理、量化精度导致的。建议先在 PC 上对现场视频做一次模拟推理把输入缩放、归一化方式调成与设备一致再分析是哪个环节丢掉了小球。10. 工程最佳实践给竞赛和项目落地都适用最后沉淀一些对竞赛项目甚至未来工程开发都有帮助的习惯。10.1 数据集和权重都要做好版本管理数据集没有版本管理是很多问题的根源。你可能上周训练出 99% 准确率今天却因为改了图片目录、重新导出后效果完全不对。建议数据集根目录用v1.0、v1.1方式命名每个训练产出的best.pt都记录对应的数据版本、是否数据增强、输入尺寸部署模型文件名也要带上尺寸和量化信息例如ball_320_int8.mud。10.2 推理循环里不要做耗时打印串口或者日志打印看起来操作简单但高频打印会严重拉低帧率。比赛现场可以把坐标写入一个小型环形缓冲区由统一模块决定是显示、存储还是发送。判断小球位置时不要在每帧print(fps)否则输出本身会影响任务时序。10.3 先跑通最简流程再优化性能我和身边的同学踩过最集中的同一个坑一开始就同时追求高精度、高帧率、复杂后处理结果多天调不通。正确顺序是先用官方 YOLO11n 权重跑通全流程确认能在 MaixCam2 上显示画面、画框再采集自己的数据训练得到专用模型最后再精细优化帧率和鲁棒性。只要链路通了后面每一步优化都有明确的观测指标不会陷入“改了一堆不知道哪步有效”的迷茫。10.4 赛前准备一个“快速恢复”脚本比赛现场最怕环境配置乱了。可以把模型文件、运行脚本、测试视频都放到设备固定目录并准备一个一键启动脚本。这样哪怕设备被复位或换新也能快速恢复运行状态。对现场裁判来说稳定的系统演示比一个“偶尔能跑高分但经常崩溃”的方案更值得信赖。11. 从这套项目里可以继续深挖什么如果你把 MaixCam2 上的 YOLO11 小球检测已经跑到 60FPS继续往下可以探索的方向很多。对我来说最推荐三个方向把单目标检测扩展成多目标跟踪例如 ByteTrack让每个小球不只是“被检测到”还能保持身份编号借助连续帧坐标做轨迹预测与物理建模比如抛物线运动估算、出界点预警这和很多赛题的进阶小问直接相关换用 YOLO11 的分割模型或姿态模型尝试在小球之外检测目标轮廓、机器人位姿拓宽硬件平台的应用场景。框架和硬件总在更新但“小模型 端侧优化 实时闭环”这套方法论不会过时。希望这篇从赛题拆解到部署优化的完整记录能帮你少走一点弯路。
返回列表