简介:这份卡车倾倒建筑垃圾检测数据集面向计算机视觉与深度学习方向的开发者、算法工程师及环保智能监控研究者,用于训练和评估目标检测模型,识别图像或视频流中卡车倾倒建筑垃圾的行为,可服务于城市监控、建筑工地管理与环保监测等场景。资源包共1023个文件,以569张jpg、39个jpeg与106张png图像为主体,覆盖不同角度、光照与倾倒阶段,另含309个xml标注文件,提供边界框坐标与类别标签,便于直接用于监督学习训练;压缩包约115.49MB,结构清晰,适合YOLOv7等检测模型快速接入。目前已有240人学习下载。借助该数据集,读者可完成从图像预处理、标注解析到模型训练与验证的完整流程,并参考mAP 0.85的检测表现,评估模型在复杂现实环境中的准确率与泛化能力,为非法倾倒行为的自动化识别提供可靠数据基础。
1. 卡车倾倒建筑垃圾检测数据集:从标注困境到可复现训练管线
城市管理里有个高频场景:渣土车在非指定区域偷偷倾倒建筑垃圾,等执法人员赶到,车早跑了。靠人盯监控不现实,一个区几千路摄像头,看不过来。于是「卡车倾倒建筑垃圾检测数据集」这类需求就冒出来了——用视觉模型自动识别卡车+倾倒动作,把事后追查变成实时告警。
但真正动手的人很快会发现,卡住你的不是模型结构,而是数据。倾倒行为在视频里只占几秒,正样本极度稀疏;卡车和普通货车外观接近,模型容易把路过车辆误判成倾倒;不同工地、不同光照、不同拍摄角度让标注一致性很难保证。这个数据集方向要解决的核心问题就三个:怎么定义「倾倒」这个动作边界、怎么在稀疏正样本下做标注、怎么让训练出来的模型在真实摄像头下不翻车。适合做智慧城管、工地扬尘监管、边缘视觉盒子的工程师,也适合想入门行为识别但被数据卡住的人。
2. 倾倒行为的数据集怎么定义:动作边界与标注粒度
2.1 为什么「倾倒」不能只标一个框
很多人第一反应是把它当成目标检测任务:标出卡车,标出垃圾堆,训练 YOLO 去检测。这个思路在 demo 阶段能跑通,但上线就翻车。原因是「倾倒」是一个时序动作,单帧里卡车可能只是停着,垃圾堆可能还没出现。你标了卡车框,模型学到的是「卡车=正样本」,结果所有路过的卡车都告警。
常见做法是把任务拆成两层:第一层做卡车检测,第二层做动作分类或时序判定。数据集标注也要对应拆开——卡车用边界框,倾倒动作用时间段(start_time, end_time)加事件标签。如果只做单帧,至少要有「卡车+车厢举升」或「卡车+尾部垃圾滑落」这种组合特征,否则单靠卡车框没有区分度。
我一般会建议在标注规范里明确写死:倾倒事件从车厢开始举升或尾部开始有物料滑落算起,到车厢回落或物料停止滑落结束。这个边界不写清楚,十个标注员能标出十种结果,后面训练全是玄学。
2.2 标注粒度选择:帧级、段级还是事件级
三种粒度对应三种成本和精度,选错了要么浪费标注预算,要么模型学不到东西。
| 粒度 | 标注内容 | 标注成本 | 适用场景 | 模型输出 |
|---|---|---|---|---|
| 帧级 | 每帧标卡车框+是否倾倒 | 高(逐帧) | 数据量小、动作短 | 单帧分类 |
| 段级 | 标出倾倒起止时间段 | 中 | 视频片段训练 | 时序动作检测 |
| 事件级 | 只标视频里有无倾倒事件 | 低 | 弱监督、预筛选 | 视频分类 |
帧级标注最贵,但如果你要做实时告警,帧级或段级是必须的。事件级适合做粗筛,比如先从几千小时视频里筛出可能含倾倒的片段,再人工精标。实际项目里我通常先用事件级做一轮弱监督预筛,把候选片段从小时级压到分钟级,再上段级精标,标注成本能降一个数量级。
2.3 正负样本比例与难负样本挖掘
倾倒行为在真实视频里可能只占千分之几,正负样本极度不平衡。如果直接拿原始分布训练,模型会倾向于全部判负,准确率看着很高,召回率惨不忍睹。
处理方式分两步。第一步在采样阶段做重采样,让正负比控制在 1:3 到 1:10 之间,不要一上来就 1:1,容易过拟合正样本。第二步做难负样本挖掘:把模型在负样本上误报高的片段挑出来,人工确认后加入训练集。这些难负样本通常是:停靠但未倾倒的卡车、缓慢行驶的渣土车、外观相似的厢式货车。
注意:难负样本挖掘要迭代做,第一轮训练完挑一批,第二轮再挑一批,通常两到三轮后误报率会明显下降。不要一次性挖太多,容易把训练集分布带偏。
3. 从原始视频到可训练数据集:抽帧、标注与格式转换
3.1 视频抽帧策略与去重
原始视频不能直接喂给标注工具,先要抽帧。抽帧策略直接影响标注成本和模型效果。
import cv2 import os import imagehash from PIL import Image def extract_frames(video_path, out_dir, fps=2, diff_threshold=8): """ 按指定fps抽帧,并用感知哈希去重 fps: 每秒抽几帧,倾倒动作建议2-5 diff_threshold: 哈希距离阈值,小于该值视为重复帧 """ os.makedirs(out_dir, exist_ok=True) cap = cv2.VideoCapture(video_path) video_fps = cap.get(cv2.CAP_PROP_FPS) interval = int(video_fps / fps) saved, last_hash = 0, None frame_idx = 0 while True: ret, frame = cap.read() if not ret: break if frame_idx % interval == 0: img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) h = imagehash.phash(img) if last_hash is None or (h - last_hash) > diff_threshold: cv2.imwrite(os.path.join(out_dir, f"{frame_idx:06d}.jpg"), frame) last_hash = h saved += 1 frame_idx += 1 cap.release() return saved这段代码的逻辑是:按目标 fps 间隔取帧,再用感知哈希判断和上一张保存的帧是否足够不同。倾倒动作持续时间短,fps 设太低会漏掉关键帧,设太高标注量爆炸。我的经验是 2 到 5 fps 之间,具体看动作快慢。diff_threshold 控制去重力度,设 8 左右能去掉大部分静止画面,又不至于把动作变化帧误删。如果摄像头是固定机位,去重效果会很好;如果是移动拍摄,哈希去重会失效,得换光流或特征点方法。
3.2 标注工具选型与标注规范落地
标注工具常见的有 LabelImg、CVAT、Label Studio。做纯检测用 LabelImg 够用,但倾倒任务涉及时序,CVAT 的视频标注模式更合适,能直接标时间段。Label Studio 适合做多模态或事件级标注。
不管用哪个工具,标注规范必须提前写死,至少包含:
- 卡车框的边界:是否包含车厢举升部分,是否包含尾部滑落物料
- 遮挡处理:卡车被遮挡超过 50% 是否还标
- 倾倒判定:车厢举升但未卸料算不算,卸料但车厢未举升算不算
- 负样本定义:停靠多久算负样本,路过但减速算不算
这些规则不写清楚,标注员之间的一致性可能只有 60% 到 70%,训练时模型学到的就是噪声。我一般会先让标注员标 50 到 100 帧,算一下一致性,低于 90% 就回去改规范,别急着铺量。
3.3 转成 YOLO 与时序标注格式
如果做检测+时序,通常需要两套标注:检测用 YOLO 格式,时序用 JSON 或 CSV。转换脚本要保证帧号和视频时间戳对齐。
import json import os def convert_to_yolo(anno_json, out_dir, class_map): """ anno_json: 每帧的标注列表,含frame_id, bbox, class class_map: 类别名到id的映射 """ os.makedirs(out_dir, exist_ok=True) with open(anno_json, 'r') as f: data = json.load(f) for item in data: frame_id = item['frame_id'] img_w, img_h = item['width'], item['height'] lines = [] for obj in item['objects']: cls_id = class_map[obj['class']] x, y, w, h = obj['bbox'] # YOLO格式:class cx cy w h,均归一化到0-1 cx = (x + w / 2) / img_w cy = (y + h / 2) / img_h lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {w/img_w:.6f} {h/img_h:.6f}") with open(os.path.join(out_dir, f"{frame_id:06d}.txt"), 'w') as f: f.write("\n".join(lines))转换时最容易翻车的是坐标系。有些标注工具输出的是左上角+宽高,有些是左上角+右下角,有些是归一化过的,有些是像素值。转换前一定先拿几帧可视化验证,别等训练 loss 不降才回头查。另外帧号对齐也要注意,抽帧后的帧号和原视频帧号不是一回事,时序标注要映射回抽帧后的编号,否则时间段全错位。
4. 训练管线搭建:从数据加载到模型选型
4.1 数据加载与增强策略
倾倒检测的数据增强不能照搬通用检测那套。水平翻转通常安全,但垂直翻转会让卡车倒扣,不真实。颜色抖动可以加,模拟不同光照。随机裁剪要小心,可能把卡车裁掉一半,反而制造噪声。
import albumentations as A train_transform = A.Compose([ A.HorizontalFlip(p=0.5), A.RandomBrightnessContrast(p=0.3), A.HueSaturationValue(p=0.2), A.MotionBlur(blur_limit=5, p=0.2), # 模拟运动模糊 A.Resize(640, 640), ], bbox_params=A.BboxParams(format='yolo', label_fields=['class_labels']))MotionBlur 是我会特意加的一项,因为真实摄像头下渣土车运动时经常有拖影,不加这个增强,模型在模糊帧上容易漏检。Resize 到 640 是 YOLO 系列的常见输入尺寸,如果边缘设备算力有限,可以降到 416 或 320,但小目标召回会掉。
4.2 模型选型:检测+时序还是端到端
两条路线。第一条是检测+跟踪+时序分类:YOLO 检测卡车,ByteTrack 跟踪,再把轨迹送进 LSTM 或 TSM 判断是否倾倒。第二条是端到端视频检测,比如用 Video Swin Transformer 或 TimeSformer 直接输出事件。
端到端精度上限高,但数据需求大、推理慢,边缘盒子跑不动。检测+时序的方案模块化,每部分可以单独优化,推理也能控制在实时范围内。我一般推荐先走检测+时序,等数据量上来了再考虑端到端。
检测模型选 YOLOv8 或 YOLOv10 都行,看你的部署工具链支持哪个。时序分类用 TSM 或轻量 LSTM 就够,输入是卡车轨迹的 ROI 特征序列,不需要太重的模型。
4.3 训练参数与损失函数调整
不平衡数据下,分类损失要加权。如果倾倒正样本只占 5%,负样本权重可以设 0.5 到 0.8,正样本权重设 2 到 5,具体看验证集召回。
yolo detect train data=dataset.yaml model=yolov8m.pt epochs=100 imgsz=640 batch=16 \ cls=2.0 box=7.5 dfl=1.5 lr0=0.01 lrf=0.01 warmup_epochs=3cls 参数控制分类损失权重,默认 0.5,不平衡时调高到 1.5 到 2.0。box 是框回归权重,一般不动。lr0 初始学习率 0.01 是常见起点,如果 loss 震荡就降到 0.005。warmup_epochs 设 3 到 5,让模型先稳住再学细节。
训练时重点看召回率而不是准确率。倾倒检测漏报比误报代价高,漏一次可能就放过一辆偷倒的车。验证集上如果召回低于 85%,优先查标注质量和难负样本,别急着调模型。
5. 避坑与排查:标注、训练、部署中的血泪经验
5.1 标注一致性差导致模型学噪声
现象:训练 loss 降不下去,验证集指标波动大,同一批数据两次训练结果差很多。
原因:多个标注员对倾倒边界理解不一致,有的标了车厢举升,有的只标物料滑落,模型在矛盾样本上反复震荡。
解决:先做标注一致性校验,抽 100 帧让多人重复标,算 IoU 和事件边界重合度。低于 90% 就回去改规范,加示例图,统一培训后再铺量。已经标完的数据,用模型预测结果反向筛查,把模型高置信但标注为负的样本挑出来人工复核。
5.2 正负样本失衡导致召回率上不去
现象:模型准确率 95% 以上,但召回率只有 60% 到 70%,大量倾倒事件漏报。
原因:原始数据正样本占比太低,模型学会了全部判负也能拿高准确率。
解决:重采样把正负比拉到 1:5 左右,分类损失加权,再叠加难负样本挖掘。如果还不行,检查正样本标注是否太保守,有些轻微倾倒被标成了负样本,模型自然学不到。
5.3 抽帧去重过度丢失关键动作帧
现象:训练集里倾倒动作不连贯,模型在验证集上对快速倾倒漏检严重。
原因:感知哈希去重阈值设太大,把动作变化帧也当重复帧删了。
解决:把 diff_threshold 从 8 降到 4 到 5,或者对正样本时间段强制保留所有帧,只对负样本做去重。更稳妥的做法是先按时间段切分,正样本段内不抽帧或高 fps 抽帧,负样本段再降采样。
5.4 部署时输入分辨率与训练不一致
现象:训练时指标很好,部署到边缘盒子后漏检严重。
原因:训练用 640,部署为了省算力改成 416,小目标卡车在低分辨率下特征丢失。
解决:训练和部署分辨率保持一致。如果必须降,训练时就按部署分辨率训,或者用多尺度训练让模型适应。另外检查预处理是否一致,归一化参数、颜色通道顺序弄反也会导致精度暴跌。
5.5 时序窗口长度设错导致动作判定失效
现象:检测框没问题,但倾倒动作分类总是误判,停靠车辆被大量误报。
原因:时序窗口太短,模型只看到卡车停着,没看到举升和卸料过程;或者窗口太长,把前后无关帧也包进来。
解决:统计正样本动作持续时间,窗口长度设成动作时长的 1.5 到 2 倍。倾倒一般持续 5 到 15 秒,窗口设 10 到 20 秒比较合适。同时加一个前置条件:只有检测到卡车且速度低于阈值时才触发时序分类,减少无效计算和误报。
6. 进阶技巧:用弱监督预筛把标注成本压下来
标注成本是这类项目最大的瓶颈。几千小时视频全精标不现实,我一般会用弱监督做两级预筛。
第一级用事件级弱标签训练一个视频分类模型,输入是抽帧后的低分辨率片段,输出是有无倾倒事件。这个模型不需要精标,只要标视频级 0/1 就行,标注速度快很多。训练数据可以先用公开的车辆行为数据集做预训练,再用少量精标数据微调。
第二级把第一级筛出的候选片段送人工精标,标段级或帧级。因为候选片段已经压缩到原始数据的 5% 到 10%,标注量大幅下降。
# 弱监督预筛伪代码 def weak_screen(video_list, weak_model, threshold=0.7): candidates = [] for vid in video_list: frames = extract_frames(vid, fps=1) # 低fps粗筛 score = weak_model.predict(frames) if score > threshold: candidates.append((vid, score)) return candidatesthreshold 设 0.7 是偏召回的,宁可多筛一些也别漏。第一级模型精度不用太高,召回 90% 以上就行,后面还有人工兜底。这个流程跑下来,整体标注成本能降 60% 到 70%,代价是多花一两天搭弱监督管线。
验证方法上,我会留一个独立测试集,按摄像头点位划分而不是随机划分。随机划分会高估指标,因为同一摄像头相邻帧很像,模型见过类似的。按点位划分才能反映跨场景泛化能力。测试集里正样本至少 200 个事件,负样本 1000 段以上,指标看事件级召回和误报率,不看帧级准确率。
我自己的习惯是每轮迭代先跑测试集,召回没到 90% 就不看精确率,因为漏报的代价比误报高太多。误报可以靠后处理规则压,比如连续 3 秒以上才告警,漏报没法补。希望帮到你。
本文还有配套的精品资源,点击获取