简介:这份工程车辆目标检测数据集面向建筑工地智能监控、智能交通与自动驾驶环境感知等方向的算法开发者与院校研究者,聚焦混凝土搅拌车、自卸卡车、挖掘机三类常见工程车辆的识别需求。资源包共902个文件,以450张JPEG实景图片和450个YOLO格式标注txt为主,另附1个yaml数据配置与1份docx说明文档,压缩包约65.83MB,可直接加载至YOLO系列等主流框架开展训练。图片取自真实建筑与运输场景,涵盖多样化车辆姿态与背景,标注边界框定位精确,类别高度聚焦,有助于提升模型在专业场景下的泛化能力。目前已有197人学习下载。读者可获得即用型训练数据、标准标注文件与配置说明,快速搭建工程车辆检测基线,并扩展至分类、安全预警与作业效率优化等衍生应用。
1. 工程车辆目标检测数据集:从工地监控到渣土车识别的落地起点
工地出入口的摄像头每天产生几十 GB 视频,但真正需要报警的事件可能只有几十条——渣土车未苫盖、挖掘机越界、混凝土搅拌车违规停放。靠人盯着屏幕看,漏报率极高,而通用 COCO 预训练模型对"挖掘机""压路机""渣土车"这些类别的识别效果,说实话,翻车是常态。原因很简单:COCO 里根本没有这些细分类别,模型见过的"truck"和工地上的渣土车在纹理、比例、遮挡模式上差异巨大。
工程车辆目标检测数据集要解决的就是这个断层。它把工地、矿区、道路施工场景里的工程车辆框出来、标好类,让 YOLO 系列或其他检测器能直接微调落地。适合谁用?做智慧工地、矿区安全监控、市政渣土车管理的算法工程师,以及想拿真实场景练手目标检测的学生。这一章先把"这个数据集到底装了什么、为什么不能拿 COCO 凑合"讲清楚,后面再拆怎么用、参数怎么调、坑在哪。
2. 工程车辆数据集里到底有什么:类别体系与标注格式拆解
2.1 工程车辆常见类别划分与场景分布
工程车辆不是一个单一类别,它至少包含以下几类常见目标:挖掘机、推土机、装载机、压路机、混凝土搅拌车、渣土车(自卸车)、汽车起重机、泵车、叉车。不同数据集根据采集场景会做取舍——矿区数据集可能侧重矿卡和挖掘机,市政数据集则更关注渣土车和搅拌车。
场景分布直接决定模型泛化能力。如果数据集全部来自白天、晴天、固定机位,训出来的模型换个阴天或侧视角就崩。我一般会先统计几个维度:拍摄时段(白天/夜间/黄昏)、视角(固定枪机/球机/车载)、遮挡比例(车辆被土堆、脚手架遮挡的程度)、目标尺度(近处大目标 vs 远处小目标)。这些统计不需要写代码,用标注工具的可视化功能过一遍就能心里有数。
类别不平衡是另一个必须提前看的点。挖掘机和渣土车通常样本最多,泵车、叉车可能只有几十张。如果直接训,稀有类别 AP 会低得没法看。常见做法是对稀有类做过采样,或者在 loss 里给稀有类更高权重。
2.2 标注格式:VOC XML、YOLO TXT 与 COCO JSON 的转换关系
工程车辆数据集常见的标注格式有三种:Pascal VOC 的 XML、YOLO 的 TXT、COCO 的 JSON。你拿到的压缩包大概率是其中一种,但训练框架可能要求另一种。先把三者关系理清:
| 格式 | 坐标表示 | 文件结构 | 典型用途 |
|---|---|---|---|
| VOC XML | xmin,ymin,xmax,ymax 绝对像素 | 每图一个 XML | 老牌检测框架、LabelImg 默认 |
| YOLO TXT | class_id cx cy w h 归一化 | 每图一个 TXT + classes.txt | YOLOv5/v8/v11 训练 |
| COCO JSON | [x,y,w,h] 绝对像素 | 单个 JSON 汇总所有图 | MMDetection、Detectron2 |
转换时最容易翻车的地方是归一化。YOLO 的 cx、cy、w、h 都是除以图像宽高后的 0~1 浮点数,如果原图尺寸记录错了,框会整体偏移。下面是一个 VOC 转 YOLO 的脚本,我用了很多次,直接抄:
import xml.etree.ElementTree as ET import os # 类别映射,必须和 classes.txt 顺序一致 classes = ["excavator", "bulldozer", "loader", "roller", "mixer_truck", "dump_truck", "crane", "pump_truck", "forklift"] def voc_to_yolo(xml_path, out_txt_path): tree = ET.parse(xml_path) root = tree.getroot() size = root.find("size") img_w = int(size.find("width").text) img_h = int(size.find("height").text) lines = [] for obj in root.iter("object"): cls_name = obj.find("name").text if cls_name not in classes: continue # 跳过未定义类别,避免训练时报 index 越界 cls_id = classes.index(cls_name) bbox = obj.find("bndbox") xmin = float(bbox.find("xmin").text) ymin = float(bbox.find("ymin").text) xmax = float(bbox.find("xmax").text) ymax = float(bbox.find("ymax").text) # 归一化并转为中心点+宽高 cx = (xmin + xmax) / 2.0 / img_w cy = (ymin + ymax) / 2.0 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}") with open(out_txt_path, "w") as f: f.write("\n".join(lines)) # 批量处理 for xml_file in os.listdir("annotations"): if xml_file.endswith(".xml"): voc_to_yolo( os.path.join("annotations", xml_file), os.path.join("labels", xml_file.replace(".xml", ".txt")) )逻辑说明:先读 XML 里的图像宽高,再把每个框的左上右下坐标转成中心点加宽高,最后除以宽高做归一化。参数说明:classes列表的顺序必须和训练时 data.yaml 里的 names 完全一致,否则类别会错位;:.6f保留六位小数是 YOLO 官方推荐的精度,太少会导致小目标框抖动。转换完务必抽查几张,用可视化脚本把框画回原图确认没偏。
3. 用 YOLOv8/v11 在工程车辆数据集上跑通训练:环境、配置与首轮结果
3.1 环境配置与数据目录组织
YOLOv8 和 YOLOv11 都走 Ultralytics 这套接口,环境配置基本一致。我一般用 conda 建一个干净环境,避免和系统里的 torch 版本打架:
conda create -n eng_vehicle python=3.10 -y conda activate eng_vehicle pip install ultralytics==8.3.0 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121装完跑一句yolo checks确认 CUDA 可用。如果显示 CPU only,检查显卡驱动和 torch 版本是否匹配,这一步不通过后面训练会慢到怀疑人生。
数据目录按 Ultralytics 要求组织:
dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml 内容:
path: /home/user/dataset train: images/train val: images/val nc: 9 names: ["excavator", "bulldozer", "loader", "roller", "mixer_truck", "dump_truck", "crane", "pump_truck", "forklift"]注意nc必须等于 names 长度,多一个少一个都会在训练启动时报错。train 和 val 的图片不能有重叠,否则验证指标虚高,上线就露馅。
3.2 训练命令与关键参数设置
首轮训练不要一上来就调复杂超参,先用默认配置跑通,确认 loss 能正常下降:
yolo detect train \ data=dataset/data.yaml \ model=yolov8s.pt \ epochs=100 \ imgsz=640 \ batch=16 \ device=0 \ project=eng_vehicle_runs \ name=baseline参数说明:model=yolov8s.pt是 COCO 预训练权重,工程车辆类别虽然 COCO 没有,但底层纹理特征可迁移,比从头训快很多;imgsz=640是默认输入尺寸,如果数据集里小目标多(远处车辆),可以提到 1280,但显存占用翻倍;batch=16在 8GB 显存上跑 640 尺寸基本安全,显存不够就降到 8 并开amp=True混合精度。
训练启动后重点看三个指标:box_loss 是否稳定下降、mAP50 是否在 20 个 epoch 后开始爬升、cls_loss 是否震荡。如果 box_loss 不降,大概率是学习率太大或标注有问题;如果 mAP50 一直卡在 0.1 以下,检查 data.yaml 路径和类别顺序。
3.3 首轮结果解读与过拟合判断
100 epoch 跑完,Ultralytics 会在 runs 目录下生成 results.csv 和混淆矩阵。先看混淆矩阵:如果挖掘机和装载机互相误判严重,说明这两类在视觉上确实接近,需要补充区分性样本或调整类别定义。再看 mAP50-95,工程车辆场景一般能到 0.5~0.7 就算可用,低于 0.4 要排查数据质量。
过拟合的判断信号:训练集 loss 持续降但验证集 mAP 在某个 epoch 后不再涨甚至下降。这时候不要急着加数据,先看验证集和训练集分布是否一致——如果验证集全是夜间图而训练集全是白天,那不是过拟合,是分布偏移。我一般会留一个和训练集同分布的验证集做模型选择,另留一个跨场景测试集做最终评估。
4. 工程车辆检测的避坑与排查:标注、类别与部署的 5 个血泪教训
4.1 标注框贴边导致训练不稳定
现象:训练前期 loss 剧烈震荡,mAP 几乎不涨。原因:部分标注框的 xmax 等于图像宽度或 ymax 等于图像高度,归一化后 w 或 h 等于 1.0,YOLO 在计算 loss 时对边界框做裁剪,产生异常梯度。解决:写脚本检查所有 label 文件,把 cx±w/2 或 cy±h/2 超出 [0,1] 的框裁到边界内,或者直接剔除这些样本。我一般会在转换脚本里加一句 clamp 操作,省得后面返工。
4.2 类别名大小写不一致导致漏检
现象:训练时提示某些类别样本数为 0,但明明标了。原因:XML 里写的是 "Excavator",classes.txt 里写的是 "excavator",转换时没做统一,导致这些框被跳过。解决:转换前先把所有类别名转小写并去空格,再和 classes 列表比对。这个坑很隐蔽,因为不报错,只是静默丢样本。
4.3 验证集混入训练集导致指标虚高
现象:验证 mAP 0.85,上线后实际漏检严重。原因:划分数据集时用了随机划分,同一段视频的相邻帧被分到训练和验证两边,模型相当于见过验证集。解决:按视频源或时间段划分,确保验证集的场景和训练集不重叠。如果数据集本身按视频组织,直接按视频文件划分最稳妥。
4.4 小目标车辆在 640 尺寸下消失
现象:远处的小型叉车、装载机检测不到。原因:640 输入下,一个 20x20 像素的目标经过 backbone 下采样后只剩几个像素的特征,检测头根本抓不住。解决:把 imgsz 提到 1280,或者在数据加载时对小目标做 mosaic 增强。如果显存不够,可以用切片推理(SAHI),把大图切成小块分别检测再合并。
4.5 部署时预处理不一致导致精度掉点
现象:Python 端验证 mAP 0.7,转 ONNX 部署后掉到 0.5。原因:训练时的归一化是除以 255,部署时忘了做,或者 BGR/RGB 通道顺序搞反。解决:把训练时的预处理步骤写成文档,部署端逐条对齐。我一般会在导出 ONNX 后用 onnxruntime 跑一遍和 PyTorch 相同的输入,对比输出差异,超过 1e-3 就说明预处理有问题。
5. 把工程车辆检测推到可用:跨场景验证与难例挖掘的实操技巧
模型在验证集上跑出好看的数字只是第一步,真正决定能不能上线的是跨场景表现。我一般会做两件事:跨场景验证和难例挖掘。
跨场景验证的做法是,另外找一段和训练集不同摄像头、不同光照的视频,抽帧后人工标 100~200 张,作为测试集。这个测试集不参与任何训练和调参,只在最终评估时用。如果 mAP 比验证集掉超过 15 个点,说明模型过拟合到训练场景,需要补充多样化数据或做更强的数据增强。
难例挖掘更直接:用训好的模型跑一遍未标注的现场视频,把置信度在 0.3~0.6 之间的检测框导出来,人工复核。这些框要么是模型不确定的正样本,要么是背景误检。把正样本补进训练集,把误检作为负样本加入,迭代两三轮,mAP 通常能涨 5~10 个点。下面是一个导出难例的脚本片段:
from ultralytics import YOLO import cv2 model = YOLO("eng_vehicle_runs/baseline/weights/best.pt") # 对视频抽帧推理,保存中等置信度结果 cap = cv2.VideoCapture("site_video.mp4") frame_idx = 0 while cap.isOpened(): ret, frame = cap.read() if not ret: break if frame_idx % 30 == 0: # 每秒抽一帧 results = model(frame, conf=0.3, iou=0.5) for box in results[0].boxes: conf = float(box.conf) if 0.3 <= conf <= 0.6: # 保存该帧和框信息,供人工复核 cv2.imwrite(f"hard_examples/frame_{frame_idx}.jpg", frame) break frame_idx += 1 cap.release()参数说明:conf=0.3是低阈值,确保不漏掉模型犹豫的框;iou=0.5是 NMS 阈值,工程车辆重叠不多,0.5 够用;抽帧间隔按视频帧率调整,25fps 视频每 30 帧抽一张差不多。导出的图片人工过一遍,正样本补标注,误检直接作为背景图加入训练集。
还有一个技巧是测试时增强(TTA)。在推理时对同一张图做水平翻转、多尺度缩放,把结果融合,通常能涨 1~3 个点 mAP,代价是推理速度慢 3 倍。如果业务对延迟不敏感,比如离线分析场景,TTA 值得开。Ultralytics 里直接model.predict(source, augment=True)就能启用。
最后说一个我自己的习惯:每次训完模型,不管指标多好,我都会拿工地现场的视频跑一遍,用肉眼过 5 分钟。指标是给论文看的,肉眼过视频才是给上线用的。很多问题——比如把黄色挖掘机认成校车、把静止的压路机漏掉——混淆矩阵里看不出来,但视频里一眼就能发现。希望帮到你。
本文还有配套的精品资源,点击获取