:dnn实战之YOLO模型推理)
文章目录前言dnn 模块一、经典YOLOv51. 训练模型并转化为ONNX2. 图片预处理3. 推理过程4. 结果分析5. 后处理5.1 去冗余5.2 可视化6. 连续推理二、新版YOLO系列1. 训练模型并转化为ONNX2. 对比YOLO11与YOLOv53. 修改“后处理”以适配YOLO114. 完整YOLO11推理过程总结前言需要下载安装OpenCV工具包的朋友请前往 此处 系统要求Windows系统LabVIEW2018兼容32位和64位。dnn 模块查找函数选板AddonsMolitecOpenCVdnn 如下图。本文主要用到 Net 类以及 blobFromImage 和 NMSBoxes 函数。一、经典YOLOv51. 训练模型并转化为ONNX训练YOLOv5 项目文件下载地址https://github.com/ultralytics/yolov5通过 Python PyTorch 训练YOLOv5模型。Python不是我的行当这部分大家自己去“折腾”吧。本例将直接使用官方提供的预训练模型yolov5s.pt 。后缀 s 代表 small即小型它使用 coco 训练集可以识别80类物体。转化OpenCV的Net类支持载入多种模型但不支持 .pt 类型。所以得到模型后首先要将其转化成ONNX格式。在YOLOv5工程根目录下有一个export.py可以用来做模型转化。把 yolov5s.pt 拷贝到工程根目录下并在此目录下打开命令终端然后执行python export.py--weightsyolov5s.pt--includeonnx--imgsz640--devicecpu(环境参考Python3.7 torch1.13.1 onnx1.14.1 torch版本不能太高否则会出问题执行完成后会在同路径下生成 yolov5s.onnx 模型文件。2. 图片预处理YOLOv5 网络模型的输入层是一个1 * 3 * 640 * 640的四维 Blob用Mat类实现用来代表一张经过预处理的彩色图片。1 代表batch数量3代表通道数后面两位是图片的尺寸。使用 dnn 模块的 blobFromImage 函数实现图片预处理如下图。图片需要归一化所以 scalefactor 设为 1/255。输出尺寸设为640 * 640其余参数按默认值。3. 推理过程使用 dnn 模块的Net类实现YOLOv5模型推理。依次用到的Net内置函数new、setInput、forward、delete。第1步载入模型。插入一个new.vi切换模式为“readNetFromONNX”然后输入 yolov5s.onnx 文件路径第2步设置输入。插入一个setInput.vi输入经过预处理的 Blob 矩阵第3步向前传播。插入一个forward.vi切换模式为“blob_name”执行后得到网络输出Blob第4步销毁任务。插入一个delete.vi销毁Net对象释放内存。一次简单的推理过程如下图。(暂不支持GPU加速请等待后续更新CUDA 加速方案现已推出详情请见 教程214. 结果分析YOLOv5 网络模型的输出层是一个1 * 25200 * 85的三维 Blob用来表示一张图片的全部推理结果。使用 to_LV 将该Blob读取到LabVIEW中并降维成 25200 * 85 的二维数组。该数组一共25200行代表25200个识别结果。每行有85个元素依次代表cxcywhconfp0 ~ p79。其中cx、cy是矩形框中心坐标w、h是矩形框的宽和高conf是框置信度p0 ~ p79 依次是80个分类的概率。5. 后处理5.1 去冗余上文所述YOLOv5 对一张图片的推理结果达25200个之多这其中存在大量的冗余。去除冗余的方法叫做 “非极大抑制” NMS也就是从重叠的矩形框中筛选出最大且置信度最高的一个。使用 dnn 模块的 NMSBoxes 函数实现该功能如下图。注意输入bboxes中每个矩形的xy是左上点而模型输出的cxcy是中心点所以需要计算转换一下。scores是每个矩形的置信度刚好对应上文中代表 conf 的那一列直接连过去作为scores输入。NMSBoxes 函数的输入输出输入类型含义bboxes二维数组当列数为4时每行4个数代表一个矩形 Rect(x, y, w, h)当列数为5时每行5个数代表一个旋转矩形 RotatedRect( cx, cy, w, h, angle)当列数为6时每行6个数代表一个旋转矩形 RotatedRect( x1, y1, x2, y2, x3, y3)scores一维数组对应bboxes中每个矩形框的置信度params簇score_threshold 是置信度阈值nms_threshold 是NMS阈值eta 是调节 NMS 阈值的衰减因子默认设为1top_k 是最大保留数等于0时忽略输出类型含义indices一维数组通过 NMS 筛选后保留下来的矩形框索引在bboxes中的行序号5.2 可视化可视化的任务是在原图片中画出经过筛选的识别框、分类名称和概率以便更直观地体现 dnn 推理结果。注意YOLOv5 网络输出的矩形框坐标是基于预处理尺寸 640 * 640 而言的。因此在原图片上绘制之前需要经过尺度转化。然后在对应的 p0 ~ p79 中找出最大概率的所在位置就是分类序号据此从名称列表里找到具体分类名称。实现过程如下图所示。NMS之前提取bboxes和scores的过程已封装成子VI至此一次完整的 “预处理 推理 后处理” 过程全部完成整体算法流程如下图。可视化过程已封装成子VI。 fit_to_center.vi 让picture控件自适应缩放并居中详见 教程36. 连续推理利用LabVIEW的循环结构从摄像头连续采样并实时进行 YOLOv5 推理。请参考工具包附带的范例examples/Molitec/OpenCV/dnn/Net_3 (ONNX_yolov5_Camera).vi注意多个Mat对象只需在While循环外初始化一次然后在循环中重复使用从而避免占用大量内存。CUDA 加速方案现已推出详情请见 教程21二、新版YOLO系列新版 YOLO 采用 Ultralytics 的框架适合 YOLOv8、YOLO11、YOLO26 等后续版本。本文接下来以 “YOLO11” 进行描述其他版本请对照参考。1. 训练模型并转化为ONNX训练YOLO11 项目文件下载地址https://github.com/ultralytics/ultralytics/tree/mainYOLO11 训练模型可以使用集成度更高的 ultralytics 库支持的 Python 版本为3.8 ~ 3.12。同样训练过程请自行完成。本例将直接使用官方提供的预训练模型yolo11s.pt 依然是80分类。转化同样要将 .pt 模型转化成ONNX格式。YOLO11 可以通过 Python 调用 ultralytics 库进行转化fromultralyticsimportYOLO modelYOLO(yolo11s.pt)pathmodel.export(formatonnx)(环境参考Python3.12 ultralytics8.3.86 torch2.6.0 onnx1.17.0 onnxslim0.1.48 onnxruntime1.21.0path 返回 onnx 文件路径。转化过程输出如下2. 对比YOLO11与YOLOv5从上述转化过程的输出信息中可以看出YOLO11与YOLOv5的输入层是一样的形状1 * 3 * 640 * 640二者的区别在输出层上。YOLO11 的输出层1 * 84 * 8400YOLOv5 的输出层1 * 25200 * 85降维成2D后YOLO11 的输出是 84行 * 8400列每一列作为一个结果。而 YOLOv5 是每一行作为一个结果。YOLO11 每一列的 84 个元素依次代表 cx、cy、w、h、p0 ~ p79。与 YOLOv5 相比没有框置信度conf。采用相同的 “预处理”进行一次 YOLO11 推理观察返回结果。如下图。3. 修改“后处理”以适配YOLO11如上文所述YOLO11 相比 YOLOv5其主要区别在于输出层。因此只需修改 “后处理” 过程。既然 YOLO11 是每列代表一个结果那么直接将2D数组转置这样就在方向上与 YOLOv5 一致既然 YOLO11 没有框置信度就用p0~p79中的最大值作为conf插入到对应位置这样就在数量上与 YOLOv5 一致如此改造后就可以直接沿用上文中 YOLOv5 的后处理子VI。但此时NMSBoxes 的 score_threshold 参数含义将变为类别概率阈值修改后的算法如下图。其实修改方法不唯一大家自己或许有更好的方案4. 完整YOLO11推理过程一次完整的 YOLO11 推理过程如下图。连续推理过程请参照 YOLOv5 尝试自行编写。总结本系列博文作为LabVIEW工具包—OpenCV的教程将以专栏的形式陆续发布和更新。对工具包感兴趣的朋友欢迎下载试用秣厉科技 - LabVIEW工具包 - OpenCV各位看官有什么想法、建议、吐槽、批评或新奇的需求也欢迎留言讨论。