简介:面向工业自动化装配、质量监控与机器人视觉引导等场景,这份工具装配检测数据集提供1,873张源自真实装配线的训练图片,覆盖枪型工具、钳型工具、尖头工具、扫描工具及手部五类目标,已统一为YOLO边界框与类别标签格式,可直接用于YOLOv5/v8等目标检测模型训练与验证。压缩包共2,000个文件,以jpg图像、txt标注文件为主,另含yaml配置与docx说明文档,整体约80.98MB,目录结构简洁,便于导入项目后快速拆分训练集和验证集。数据集涵盖多角度、多光照的工业操作样本,标注贴合真实装配环境,可辅助搭建工具识别模型,优化装配流程、降低人工干预,也适合作为职业院校智能制造相关课程的实训素材。目前已有188人浏览学习,适合算法工程师、工业视觉开发者及教学人员快速获取标准化数据。
1. 工具装配检测数据集:一个 ZIP 里装好的工业目标检测起点
当你想把一个 YOLO 模型落地到装配线工具检测上,最头疼的往往不是训练代码,而是没有带标注的数据。工具装配检测数据集就是从这个真实需求来的——一个 zip 包里包含了来自工业装配场景的 1873 张训练图片,标注了枪型工具、手部、钳型工具、尖头工具、扫描工具五个类别,并直接给出 YOLO 格式的边界框标签。这意味着你不需要手工画框标数据,解压后改一条路径就能开始用 YOLOv5/YOLOv8 训练。它适合两类人:一是刚接触工业目标检测的开发者,想找一个干净、类别不多、立刻能上手的练手数据集;二是已经在做装配视觉项目、急需一组真实场景预训练样本的工程师。后者的坑在于“看起来能跑”和“真的能上线”差距很大,这个差距我会在后面的避坑章节专门展开。
2. 读懂数据集的目录与标注:1873 张图背后的 YOLO 格式细节
在动手训练之前,先做两件事:把 zip 解开后把所有文件放整齐,再验证标签对应关系。跳过这一步的人,后面八成要翻车。工业数据集的“可用”不只是能解压,而是目录结构、标签格式、类别映射全部对得上。这一章我按我实际拆包的习惯来写。
2.1 Roboflow 导出文件命名里藏着的源信息
解压后你大概率会看到这样的文件名:
1591587432198_jpg.rf.6cee4fe03f30966306dcc3e8d7360995.jpg WIN_20240614_04_47_55_Pro_mp4-0067_jpg.rf.f6a327b2c6d792d1634bae74081d9354.jpg注意中间那段_jpg.rf.,rf是 Roboflow 导出的惯例,它说明这批图是从视频帧里截出来后在 Roboflow 平台上标注的。前一段时间戳或视频文件名(比如WIN_20240613_04_24_07_Pro_mp4-0095)是截图来源,后面的 32 位十六进制是平台分配的样例 ID。这对使用没影响,但能解释两件事:为什么有些图看起来像连拍视频帧,以及为什么压缩包里没有统一的原始目录结构。
Roboflow 标准导出通常长这样:
data.yaml train/images/xxx.jpg train/labels/xxx.txt valid/images/xxx.jpg valid/labels/xxx.txt test/images/xxx.jpg test/labels/xxx.txt下载的 zip 里如果少了 valid 或 test 目录,别慌,用后面的脚本补一刀就行。先确认一下实际结构,再决定要不要重建目录。你可以用一条命令把当前结构打出来:
find . -maxdepth 2 -type d | sort如果只有一堆散装 jpg 和 txt,那就意味着数据集的划分需要自己完成。这里有 1873 张训练图,按 8:1:1 的比例划分是一个常用做法:1500 张左右进训练、180 张左右进验证、剩下进测试。工业场景样本少,测试集可以不要太大,至少保证验证集能代表装配线不同工位的角度分布。划分脚本我放在后面的 2.4 小节。
2.2 五个类别与类别 ID 的映射表
数据集标注了五个类别,YOLO 标签里的一串数字没有意义,必须配合data.yaml里的names顺序使用。下面是我对照原始标签整理的中英映射:
| 类别ID | 英文标签 | 中文含义 | 典型出现场景 |
|---|---|---|---|
| 0 | gun-type tool | 枪型工具 | 胶枪、螺丝枪、点胶枪等 |
| 1 | hand | 手部 | 工人握持工具的手 |
| 2 | pliers-type tool | 钳型工具 | 尖嘴钳、斜口钳、压线钳 |
| 3 | pointed tool | 尖头工具 | 螺丝刀、锥子、探针 |
| 4 | scanning tool | 扫描工具 | 扫码枪、标签扫描器 |
为什么把手部也当一类?因为装配合规检查的规则常常依赖工具与手的位置关系——检测到手但没检测到工具,代表工人操作中断;检测到工具但没检测到手,可能是工具悬挂或放置状态。这个数据集把 hand 作为独立类别,就是方便你做这类逻辑判断,而不是只输出工具框。
类别 ID 的顺序以data.yaml里names列表的第一个为准。如果你是直接把这里五个类别映射到自己项目里,务必先读 names。我见过有人把第 3 类当成第 0 类,因为下意识按字母序排了类别,结果训练出来的模型所有枪型工具都标成尖头工具,这就是典型的 ID 错配。
2.3 用 Python 把标签画回图片验证坐标
YOLO 标签每行是五个数字,对应类别ID 中心点x 中心点y 宽度 高度,坐标全部除以图片宽高做了归一化。格式没问题时,最简单可靠的验证方式是画框回看。下面是一段把标签画回图片的 Python 代码:
import cv2 image_path = "train/images/1591587432198_jpg.rf.6cee4fe03f30966306dcc3e8d7360995.jpg" label_path = "train/labels/1591587432198_jpg.rf.6cee4fe03f30966306dcc3e8d7360995.txt" img = cv2.imread(image_path) h, w = img.shape[:2] names = ["gun-type tool", "hand", "pliers-type tool", "pointed tool", "scanning tool"] with open(label_path, "r") as f: lines = f.readlines() for line in lines: cls, xc, yc, bw, bh = map(float, line.split()) x1 = int((xc - bw / 2) * w) y1 = int((yc - bh / 2) * h) x2 = int((xc + bw / 2) * w) y2 = int((yc + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, names[int(cls)], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) cv2.imwrite("check_bbox.jpg", img)这里的核心是把归一化坐标乘回图片宽高。xc - bw/2算左边界,yc - bh/2算上边界,减出来是左上角,+是右下角。注意最终要转成int再交给 OpenCV 绘制,否则画线函数会报类型错。如果画出来的框明显偏离工具或框住了半个背景,先怀疑标签文件和图片文件名是否一一对应,再怀疑类别映射 ID 是不是错位。
我一般会随机抽 20 张图跑一遍这个脚本,确认五类都出现且框位置合理再进入训练。这一步不能跳,因为它能同时发现文件名配对错误和标签解压缺失两个问题。
2.4 补齐缺失的 train/valid/test 目录
如果压缩包解压后没有按 Roboflow 标准目录分好,可以用一个 Python 脚本重建。常见做法是先把所有图片扩展名和同名 txt 配好,再按 8/1/1 划分:
import os import random import shutil random.seed(42) img_dir = "images" # 散装图片目录 lbl_dir = "labels" # 散装标签目录 out_dir = "dataset" # 输出目录 images = [f for f in os.listdir(img_dir) if f.endswith((".jpg", ".png"))] random.shuffle(images) n_train = int(len(images) * 0.8) n_valid = int(len(images) * 0.1) for i, img_name in enumerate(images): if i < n_train: subset = "train" elif i < n_train + n_valid: subset = "valid" else: subset = "test" base = os.path.splitext(img_name)[0] txt_name = base + ".txt" if not os.path.exists(os.path.join(lbl_dir, txt_name)): continue dst_img = os.path.join(out_dir, subset, "images", img_name) dst_txt = os.path.join(out_dir, subset, "labels", txt_name) os.makedirs(os.path.dirname(dst_img), exist_ok=True) os.makedirs(os.path.dirname(dst_txt), exist_ok=True) shutil.copy(os.path.join(img_dir, img_name), dst_img) shutil.copy(os.path.join(lbl_dir, txt_name), dst_txt)这段脚本的关键参数是random.seed(42),它保证每次划分结果一致。如果你不改种子,同一批数据怎么重跑结果都一样,方便复现训练。还有一个常见误区:划分时只根据图片文件名 shuffle,导致连续的视频帧全部进训练集、验证集里全是另一种镜头角度。为了避免这个问题,最好先按文件名的来源前缀分组再划分,比如前缀WIN_20240613_04_24_07_Pro是一段视频,1591587432198是另一段。分组划分的完整逻辑我会在第 4.3 节再单独讲,因为这是工业数据泄漏最隐蔽的地方。
3. 把数据集跑通:YOLOv8 训练工具检测模型的关键参数与调优
这一章从写 YAML 到跑出 best.pt,全程用 YOLOv8 举例,同时会说明换成 YOLOv5 或 YOLOv12 时哪些参数可以直接平移。内容偏实操,先把配置文件和参数吃透,再谈训练和调优。
3.1 数据配置 YAML:路径、names 顺序与训练集划分
YOLO 系列框架通过一个 YAML 文件读取数据集配置。在项目根目录新建tool_assembly.yaml:
path: ./dataset # 数据集根目录 train: train/images # 训练图片相对路径 val: valid/images # 验证图片相对路径 test: test/images # 测试图片相对路径 names: 0: gun-type tool 1: hand 2: pliers-type tool 3: pointed tool 4: scanning toolpath是绝对路径或相对路径,YOLOv8 会把它和train、val拼接起来找图片。这里最容易出错的是path末尾千万别加多余的斜杠,train字段写train/images,不是./train/images,两个写法多数时候都能跑通,但会有人把train和val写成train.txt这种文件列表格式,这种旧写法 YOLOv8 已经不太认。names必须从 0 开始且顺序和标签文本第一个数字一一对应,否则类别标签全部错位。
提示:如果 zip 包在 Windows 网盘里转了一圈,注意
data.yaml的换行符和路径里的中文字符。YOLO 不识别带中文和空格的绝对路径,建议整个项目目录放在纯英文路径下。
如果你下载的 zip 自带data.yaml,也不要直接用,先打开看一眼names顺序和你手里项目代码里的 class 映射表是否一致。工业项目经常要加一个“背景/其他”,那就在names后面追加第 5 类,同时把丢弃的背景框补标进去。没有背景类时,阈值稍低就容易把无关物体当工具。
3.2 训练命令怎么选参数:模型规格、输入尺寸与批量
YOLOv8 官方安装好后,一条命令就能开始训练:
yolo train \ data=tool_assembly.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ patience=20 \ project=runs_tool \ name=exp1参数含义:model=yolov8n.pt是 COCO 预训练权重,n 代表 nano 版本,速度最快但精度有限;显存充足建议换成yolov8s.pt,工业小目标场景通常比 nano 高 2~3 个 mAP 点。imgsz是训练输入边长,默认 640。由于工具在画面中占比常常不大——一把螺丝刀可能只有 40×200 像素——我一般会在工业场景提到 800,代价是显存占用增加,batch 按比例减半,比如 16 变 8。patience=20是早停参数,验证集指标连续 20 个 epoch 不涨就停,避免浪费时间。
训练结束后,结果在runs_tool/exp1/目录下。重点看三个东西:weights/best.pt、results.png、confusion_matrix.png。results.png里如果看到 val loss 后期不降反升,就是过拟合信号。这时优先做两件事:打开第 5 章说的增强参数,或者把patience从 20 改回 10,别等模型彻底飞了才停。
3.3 训练日志里的指标解读:mAP50 与 mAP50-95 谁更可靠
YOLO 训练日志里最常见的两个指标是mAP50和mAP50-95。mAP50算的是 IoU 阈值 0.5 下的平均查准率,相对宽松;mAP50-95把 0.5 到 0.95 之间 10 个阈值全算一遍再取平均,更严格。对工具装配检测来说,mAP50 更重要一点,因为装配线只关心你“框得够准”,不关心边界框和真实框的重合度是 0.7 还是 0.9。工具轮廓不是圆形物体,标注框是人手画的矩形,本身存在框不严的误差。所以当 mAP50 到 0.9 而 mAP50-95 只有 0.5 时,不用恐慌,先把 mAP50 稳住。
但有一个例外:如果你的模型最后要用来计算工具和手的相对位置,比如判断“手是否握住工具”,对两个框的交并比很敏感,这时候就得把 mAP50-95 也拉上去。方法是把imgsz从 640 提到 800,并将batch降到 8,再跑 50 个 epoch。原因是小尺寸输入会压缩小工具的边界细节,IoU 计算稍微偏差一点,mAP50-95 的分数就会掉得很明显。
3.4 在未标注视频上做第一轮推理验证
训练完别急着看指标表格,先拿一段现场装配视频做推理,肉眼判断才靠谱。模型指标好只能说明它在评估集上表现好,没见过的新视频才是真正考题。
yolo predict \ model=runs_tool/exp1/weights/best.pt \ source=test_video.mp4 \ conf=0.3 \ iou=0.5 \ save=True \ project=runs_tool/predictconf=0.3意味着置信度低于 30% 的框会被过滤。视频场景里背景杂、有遮挡,0.3 有时不够,我会降到 0.2 看一轮误检数量再回调。iou=0.5是 NMS 去重阈值,框重叠超过 50% 时保留置信度更高的那个。工具互相叠放时,iou可以提到 0.6,不然同一个钳子会被输出两个框。
推理结果视频跑一遍,很快就能看到这个数据集的局限:有些图来自视频帧,模型对完全没见过的光线、水杯、工作台边缘会有误报。这些不是模型 bug,是后续要重点收集的数据盲区。
4. 避坑指南:工具装配数据集训练中的五个翻车现场
下面五个坑是复现过程中最容易踩的,每个都按「现象 → 原因 → 解决」来写,都是我实际遇到或看到别人踩过的。
4.1 目录结构缺失:zip 解压后只剩散装文件
现象:用yolo train直接指定data=tool_assembly.yaml,控制台报错AssertionError: train: No labels in .../train/images,打开目录一看全是 jpg,没有对应的 txt。
原因:从 Roboflow 导出的 zip 在解压时如果被网盘工具重命名了顶层目录,原本的train/labels目录没有被正确释放,图片和标签各住在不同层级。或者下载的是“图片+标签打包版”,需要自己配对。
解决:先运行find . -name "*.txt" | head看标签文件是否已经解压出来。如果有,直接用上一章的目录重建脚本,把图片和标签按train/ valid/ test/重新拷贝一次。注意脚本里的base = os.path.splitext(img_name)[0],如果图片是.jpg而标签是.JPG.txt这种大小写不一致,要先统一后缀再配对。
4.2 类别 ID 错配:标签文本里的 0 并不是枪型工具
现象:训练时 loss 下降正常,mAP50 也能到 0.85,但推理时发现:螺丝枪被识别成“手”,扫码枪被识别成“枪型工具”。看标签文件,类别数字对不上。
原因:标签文件里的第一列数字只代表序号,实际含义完全取决于data.yaml里的names列表顺序。这份数据集里 gun-type tool 的 ID 是 0,hand 是 1。如果你在训练代码里手动把类名排序成["hand", "pliers-type tool", ...],模型学到的是“0 号特征是手”,推理时自然全错。
解决:用第 2.2 节的映射表逐项核对data.yaml,并且把names写死在这个文件里,不要在训练脚本里再改一次。推理代码里加载模型前后也要用相同的映射顺序。最稳妥的办法是在data.yaml所在目录放一个class_names.txt,内容和names完全一致,供后续部署引用。
4.3 帧级近重复样本:模型 mAP 虚高但上线即翻车
现象:训练集上 mAP50 高达 0.97,验证集也不错,到现场一跑,只要光线变化稍大就漏检。测试集的准确率和现场表现完全不成正比。
原因:这个数据集的 img 文件名里有很多WIN_20240613_04_24_07_Pro_mp4-xxxx前缀,说明部分样本是从同一段视频中按帧抽取的。同一段视频相邻帧高度相似,随机划分后很可能把同一时刻的近似帧同时分进训练和验证集,造成模型记忆而不是泛化。训练指标好看,现场直接现原形。
解决:按来源前缀分组划分,而不是按单文件随机划分。分组逻辑示意如下:
groups = {} for f in os.listdir(img_dir): prefix = f.split("_jpg")[0] # 去掉 .rf 哈希 groups.setdefault(prefix, []).append(f)prefix取_jpg之前的来源段,比如WIN_20240613_04_24_07_Pro_mp4-0095,这样同一段视频的多帧就聚到同一组。划分时把 group 整体按 8:1:1 分到 train/valid/test,保证同一段视频的帧不会同时出现在两个集合里。这样验证集才能真正代表模型没见过的新样本。
4.4 训练 loss 震荡收敛不动:mosaic 增强导致的小目标丢失
现象:前面 30 个 epoch 一切正常,之后 val loss 开始上下抖动,训练曲线像个波浪线,等 patience 触发了早停,但 best.pt 依然很差。
原因:YOLOv8 默认开启 mosaic 数据增强,它把四张图拼接成一张。当画面里有大量小尺寸工具时,mosaic 会进一步把目标缩小,模型学不到有效纹理。到了训练后期,mosaic 的随机性又容易干扰收敛。
解决:调整关闭 mosaic 的时机和比例。在 YOLOv8 训练配置里通过close_mosaic参数控制,比如训练 100 个 epoch 时设置close_mosaic=10,代表最后 10 个 epoch 关闭 mosaic,让模型在接近真实分布的数据上收尾。另外把mosaic=0.5左右调低,比直接关掉更稳,避免训练轮数不够时丢失多样性。
4.5 推理阈值没调:工具背面和阴影全成了误检
现象:模型把桌上倒扣的钳子、地上的影子、甚至反光的金属台面都框出来。单张看图概率还都大于 0.3,无法用低置信度过滤简单解决。
原因:工业装配场景里,很多工具的背面与正面纹理差异不大,加上灯光直射会产生大面积高光,训练集里这类负样本太少,模型只能用“色彩偏亮、形状偏长”这些粗特征判断,置信度虚高。
解决:分三层解决。第一层,推理参数把conf从默认 0.25 提到 0.45,先过滤一部分低质量框。第二层,在预测代码里加一个尺寸过滤器,宽度小于图片宽 10% 的框直接丢掉。第三层,收集几十张只有背景、没有工具的负样本图,放进数据集的train/images并生成空标签 txt,让模型学到“这个场景不输出框”。空标签文件在 YOLO 里允许存在,直接把 txt 留空即可。
5. 用数据增强救活小样本:类别不均衡与泛化能力提升
在只有 1873 张图的小数据量场景里,类别分布几乎不可能平均。增强手段要用在刀刃上,而不是盲目堆参数。这一章先把类别统计做出来,再谈增强怎么配。
5.1 先查类别统计:用脚本摸清每类目标的占比
不管网上怎么说,我拿到数据集的第一件事永远是统计。写个脚本扫一遍 label 目录:
import os from collections import Counter label_dir = "dataset/train/labels" obj_counter = Counter() img_counter = Counter() for txt in os.listdir(label_dir): if not txt.endswith(".txt"): continue seen = set() with open(os.path.join(label_dir, txt), "r") as f: for line in f: cls = int(line.split()[0]) obj_counter[cls] += 1 seen.add(cls) for cls in seen: img_counter[cls] += 1 names = ["gun-type tool", "hand", "pliers-type tool", "pointed tool", "scanning tool"] for cls in range(5): print(f"{names[cls]}: objects={obj_counter[cls]}, images={img_counter[cls]}")这里两个数字是有区别的:objects是边界框总数,images是包含该类的图片数量。做数据增强时要看的是images,因为一幅图里如果有 10 把螺丝刀,flip 增强只能让模型多学一种角度,并不会带来 10 倍的新知识。以工业装配的经验看,hand 通常是占比最高的一类,因为每张操作图里几乎都有手;pointed tool 或 scanning tool 会明显偏少。如果某类images数少于总图片数的 15%,就要针对性处理。
5.2 内置增强参数:mosaic、mixup、fliplr 怎么配合
YOLOv8 的增强参数可以在训练命令里直接覆盖。最常用的一条命令是这样的:
yolo train data=tool_assembly.yaml model=yolov8s.pt \ epochs=100 imgsz=640 batch=16 \ flipud=0.0 fliplr=0.5 \ mosaic=0.8 mixup=0.2 \ close_mosaic=10fliplr=0.5表示 50% 概率水平翻转,钳子和枪型工具左右对称,这个增强安全且几乎不会失效。flipud=0.0保持关闭,因为装配线上方的摄像头不会看到倒置的工具,强行翻转会引入不符合物理规律的样本。mosaic=0.8是拼接增强,适合增加背景多样性。mixup=0.2混合两张图,能在类别不均衡时让模型更不易过拟合。
注意增强参数有边际递减:mosaic=1.0和mosaic=0.8训练效果差距极小,反而可能让训练更慢。工业项目里第一优先是fliplr和scale(缩放扰动)。如果显存只有 8G,建议优先只开fliplr=0.5和mosaic=0.5。
5.3 数据裁剪与复制粘贴:稀缺类别最后补救
增强参数解决不了某类样本数量从 30 张变成 60 张的质变。对pointed tool这种稀缺类,常见做法是复制粘贴增强:从原图截出目标区域,贴到另一张只含背景的图里,同时复制标签坐标。写一个极简版本:
import cv2 import numpy as np def paste_object(src_img, src_label, dst_img, dst_label_path, class_id): h, w = dst_img.shape[:2] xc, yc, bw, bh = map(float, src_label.split()[1:]) x1 = int((xc - bw / 2) * w) y1 = int((yc - bh / 2) * h) x2 = int((xc + bw / 2) * w) y2 = int((yc + bh / 2) * h) obj = src_img[y1:y2, x1:x2] scale = 0.7 + 0.6 * np.random.rand() obj = cv2.resize(obj, None, fx=scale, fy=scale) # 新位置避开中心区域,模拟桌面边缘 nx = 0.2 + 0.6 * np.random.rand() ny = 0.2 + 0.6 * np.random.rand() obj_h, obj_w = obj.shape[:2] new_x1 = int((nx - 0.5) * (w - obj_w)) new_y1 = int((ny - 0.5) * (h - obj_h)) dst_img[new_y1:new_y1 + obj_h, new_x1:new_x1 + obj_w] = obj norm_x = (new_x1 + obj_w / 2) / w norm_y = (new_y1 + obj_h / 2) / h norm_w = obj_w / w norm_h = obj_h / h with open(dst_label_path, "a") as f: f.write(f"{class_id} {norm_x:.6f} {norm_y:.6f} {norm_w:.6f} {norm_h:.6f}\n")这个脚本的边界在于:粘贴位置是纯随机的,没有考虑“手应该握着工具”“工具不能悬空”的业务规则。工业检测模型只学视觉特征,暂时不需要物理合理性,但如果后续要做合规逻辑判断,手工合成的样本只能用来解决误检问题,别指望靠它训练出“手-工具关系”的语义理解。生成后必须重新跑一遍第 2.3 节的画框脚本,肉眼确认没有半截贴图。
5.4 早停与收敛判断:别让增强拖慢训练
增强开多以后,训练时间会变长,epochs=100可能 40 个 epoch 后就不再提升。这时不要无脑等完 100 个 epoch。我的习惯是同时监控results.png里的val/box_loss和metrics/mAP50(B):当 mAP50 连续 15 个 epoch 不再上升且波动小于 0.01,就手动用patience=15早停。
这个数据集的工业价值在于适配真实现场。如果训练阶段发现 mAP50 很高但 val loss 偏高,别急着调参,先回到第 4.3 节的按来源分组划分,把数据泄漏堵上,再回来谈精度。数据泄漏导致的虚高指标是工业场景最隐蔽的坑,模型上线前再发现就晚了。
6. 进阶验证:把模型接到 RTSP 视频流里做合规性检查
模型训完只是第一步,落地到装配线才算结束。最后分享一个我一直在用的验证方法:用训练好的best.pt跑一段实时摄像头流,而不是只跑测试集图片。这一步能直接把第 4 章说的“现场翻车”提前暴露出来。
6.1 用批处理脚本跑视频文件看稳定性
先不接真实摄像头,拿一段录像跑分帧推理,观察连续帧输出是否稳定。如果某几帧工具消失、下一帧又出现,基本是阈值和类别不匹配的问题。
from ultralytics import YOLO model = YOLO("runs_tool/exp1/weights/best.pt") results = model.predict( source="assembly_line.mp4", stream=True, conf=0.35, iou=0.5, imgsz=800, classes=[0, 1, 2, 3, 4], verbose=False )stream=True是惰式加载器,逐帧产出结果,不会一次性把整个视频读进内存。classes参数可以用来先只输出需要的类别。在实时验证中,我会给每类单独统计数量,比如判断:hand 类连续 10 帧出现,但 gun-type tool 类一直为 0,说明工人拿错工具或者工具被身体遮挡,这种逻辑很适合做装配合规检查。
6.2 实时流推理的两种做法
接 RTSP 摄像头和控制台一样,把source改成rtsp://user:pass@ip:554/stream1即可。但工业现场网络不稳定,重连逻辑比模型精度更影响效果。YOLOv8 的predict在推流断开时直接抛异常,我建议在业务代码里套一个断线重连:
import cv2 import time from ultralytics import YOLO model = YOLO("best.pt") cap = cv2.VideoCapture("rtsp://admin:123456@192.168.1.64:554/Streaming/Channels/1") while True: if not cap.isOpened(): print("reconnect...") time.sleep(2) cap.open("rtsp://admin:123456@192.168.1.64:554/Streaming/Channels/1") continue ret, frame = cap.read() if not ret: cap.release() continue results = model(frame, conf=0.35, imgsz=800) for r in results: for box in r.boxes: cls = int(box.cls[0]) conf = float(box.conf[0]) print(f"cls={cls}, conf={conf:.2f}")这里有个容易被忽略的细节:model(frame, imgsz=800)会先把输入拉伸到 800 再推理,但输出框坐标已经映射回原始 frame 坐标系,不需要手工换算。另外rtsp的用户名密码都是 URL 编码过的,密码里有@或/必须转义,否则 cv2 打开失败。那以后我每次训练完都不直接凭 mAP 下结论,而是强制用 RTSP 流跑十分钟,统计各类的漏检和误检比例,记录在训练卡片上。再好的指标,在现场视频里经不住一帧闪烁就会暴露。希望帮到你。
本文还有配套的精品资源,点击获取