news 2026/10/4 4:29:45

城市道路井盖破损丢失数据集VOC+YOLO格式及YOLOv8训练避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
城市道路井盖破损丢失数据集VOC+YOLO格式及YOLOv8训练避坑指南

简介:面向城市道路巡检与目标检测应用场景,该压缩包提供一套完整的井盖破损/丢失数据集,含1377张真实道路井盖图像,覆盖4个类别共1722个标注框,并同时提供Pascal VOC xml与YOLO txt两种标注格式,方便直接用于YOLO、SSD等常见检测模型的训练与验证。压缩包共2000个文件,以xml标注文件与txt标签文件为主,整体大小约212.35MB,适合有一定深度学习基础的研究者或算法工程师快速开展模型微调与效果评估。整个数据集使用labelImg工具人工标注,类别划分清晰,已吸引427人学习/下载。借助该数据集可省去自行采集与标注的耗时,直接获得与主流框架兼容的训练样本,便于复现井盖破损、丢失等视觉检测任务并验证算法鲁棒性。

1. 城市道路井盖破损丢失数据集VOC+YOLO格式1377张4类别:这个 zip 到底能帮你省多少事

“城市道路井盖破损丢失数据集VOC+YOLO格式1377张4类别.zip”,这个词看上去像个普通压缩包,但在市政巡检项目里,它代表一套能直接进入训练流程的双格式标注样本。1377 张道路影像,按 VOC 和 YOLO 两套规范标好四类井盖状态,拆开就能喂给检测网络。适合接市政养护、智慧路灯杆联动、道路病害巡检这类项目的人,先拿它做预训练和方案验证。做过井盖检测的都知道,标注是最大成本,市面很少有成套的双格式井盖数据能复现。这篇文章我按自己的落地流程写:先拆目录、再做 VOC 转 YOLO、然后训一个 YOLOv8 基线,最后把那些只在真实街道数据上出现过的坑列出来。

2. 先拆数据集:4 类标注逻辑与 VOC/YOLO 双格式目录解析

拿到这套 zip 后,我不会急着解压就训练。先做两件事:定类别、对文件名。之所以先定类别,是因为 YOLO 的 txt 标注写的是类别编号,不是类别名;如果类别顺序和实际标注对不上,后面所有指标都是假的,我在这上面栽过不止一次。

2.1 四类标什么:为什么把“完好”也放进来

市政井盖检测常见的四类分法是:完好、破损、丢失、异动/位移。

“完好”是负样本类。训练时它能让模型学会“这里有个井盖,但不用报修”,避免把所有井盖都判成破损。市政项目真正上线后,漏报破损的代价远大于误报完好,所以负样本类必须留足占比,最好占三到四成。只标三类的方案我不推荐,那种模型会把路基接缝、沥青修补块全当成破损,巡检画面框满红框,完全没法用。

“破损”指井盖表面裂缝、缺角、塌陷变形。这个类别的难点在拍摄角度:侧视角下,远处破损和近处普通裂纹纹理高度相似,要靠局部亮度差异和边缘连续性去分。“丢失”代表井盖不在井口位置,露出井洞,责任级别最高;它和“破损”的边界常常是同一个井盖在不同时刻的状态。盖子还在但有裂缝叫破损,盖子被冲走叫丢失,标注口径如果在两份数据里不一致,模型会学得相当痛苦。

“异动/位移”指井盖整体错位但未形成洞口,比如被碾压翘起、平移。这类样本数量通常最少,也最容易和破损混淆。如果这套 zip 里这一类比预想少,我的习惯是把它并入“破损”,先用二分类把“要不要派人修”判断干净,后续专项检测再细分。

这里还有一条反面经验:有些数据为了凑类别数,把完好井盖标成“其他”,把树坑和污水格栅也加进来,类别数虚高,真实信息量反而下降。拿到 zip 后如果发现标签里出现不在四类语义内的名称,第一反应不是改脚本兼容它,而是向来源确认这到底是噪声还是新增需求。

2.2 VOC 与 YOLO 目录怎么对应:文件命名是第一个容易被坑的地方

双格式 zip 解压后通常能看到两类目录:一类是 VOC 的 annotations/images 布局,一类是 YOLO 的 images/labels 布局。VOC 目录里每个标注是一个 XML 文件,文件名和图像同名;YOLO 目录里每个标注是 txt 文件,也要求与图像同名。常见结构是这样:

manhole_1377/ ├── VOC │ ├── JPEGImages/ │ │ ├── 00001.jpg │ │ └── ... │ ├── Annotations/ │ │ ├── 00001.xml │ │ └── ... │ └── ImageSets/Main/ │ ├── train.txt │ ├── val.txt │ └── test.txt └── YOLO ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/

重点不在目录名是 JPEGImages 还是 images,而在于 YOLO 的 labels 与 images 文件名前缀完全一致。有的 zip 为了压缩省空间,图像用短文件名、标签用长文件名,比如 image00123.jpg 对应 image00123.xml,但 YOLO 侧却把“.jpg”去掉直接存 .txt,训练器扫描时找不到匹配,就会一直卡在 Scanning labels。

我还会顺手看一眼 ImageSets/Main 里的划分。VOC 侧的 train.txt/val.txt 是训练集和验证集划分的依据,YOLO 侧如果自己又随机分了一次,两边最好对齐用同一批 id。如果 zip 里没给划分文件,我一般按 8:2 随机分,但 seed 必须写死,保证复现。

提示:zip 文件先在本地完整解压一次,确认没有长路径和全半角符号混用,否则某些解压工具会在长路径处静默跳过文件,训练时才发现图像总数差了 20 张。

2.3 开箱后的五道校验:进入训练前先跑一遍

我默认做五道校验,不需要逐张看,只跑脚本扫一遍。

校验一,类别表。grep 所有 xml 里的<name>,把不重复的类别名列出来,确认就是 4 个目标类,没有错标类名。类别名大小写不一致也会炸掉数据准备过程。

grep -h "<name>" VOC/Annotations/*.xml | sed 's/<[^>]*>//g' | sort | uniq -c

校验二,文件名一致。用 diff 或 for 循环扫描两份目录。ZIP 在 Windows 解压时偶尔把 XML 文件名里的字母转了大小写,Linux 下训练器区分大小写,结果一半标注读不上。

find VOC/Annotations -name "*.xml" | wc -l find VOC/JPEGImages -name "*.jpg" | wc -l # 两行结果如果不相等,先确认是不是有子目录和隐藏文件

校验三,空标签。一个 txt 内容为空,表示该图没有任何目标。YOLO 允许背景图,但如果空标签有几百张,就要想想真实场景是否真存在这么多无井盖路段。校验四,图像宽高。查看图片实际尺寸和 xml 里<size>是否一致。有些数据集从视频抽帧后 resize 过,但 xml 没跟着改,VOC 转 YOLO 时这一步必错。校验五,坐标越界。遍历 xml 的 bndbox,把 xmin 小于 0、xmax 大于图像宽的情况列出来。高空正视角图像里尤其常见,因为标注员把屏幕外的目标也标了。

注意:不要只看文件名里的 1377 就默认数量和划分正确,解压后 image 目录的实际 jpg 数和 xml 数要专门数一遍。如果 zip 打包时把 xml 塞在VOC/Annotations/extra/这种子目录里,光数根目录也会出错,要用 find 扫全盘。

3. 把 VOC 转成 YOLO 格式:转换脚本与四个边界坑

VOC 标注是像素坐标的 xmin/ymin/xmax/ymax,YOLO 是归一化的中心点加宽高。转换逻辑不难,难在核对边界:坐标是否越界、类别顺序是否错位、空标签是否被漏掉。

3.1 最小可用的 voc_to_yolo 转换脚本

我写一个 Python 最小版本,不依赖第三方库,xml.etree.ElementTree就够:

import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_path, out_dir, class_names): tree = ET.parse(xml_path) root = tree.getroot() size = root.find("size") img_w = int(size.findtext("width")) img_h = int(size.findtext("height")) if img_w <= 0 or img_h <= 0: print(f"[skip] {xml_path.stem}: bad image size") return lines = [] for obj in root.findall("object"): name = obj.findtext("name") if name not in class_names: print(f"[warn] {xml_path.stem}: unknown class {name}") continue class_id = class_names.index(name) b = obj.find("bndbox") xmin = float(b.findtext("xmin")) ymin = float(b.findtext("ymin")) xmax = float(b.findtext("xmax")) ymax = float(b.findtext("ymax")) # 越界坐标先裁回图像范围,避免归一化后出现负数或大于 1 xmin = max(0.0, min(img_w, xmin)) xmax = max(0.0, min(img_w, xmax)) ymin = max(0.0, min(img_h, ymin)) ymax = max(0.0, min(img_h, ymax)) # 有的标注工具会写出 xmin > xmax 的脏数据,这里统一规整一次 if xmin > xmax: xmin, xmax = xmax, xmin if ymin > ymax: ymin, ymax = ymax, ymin w = xmax - xmin h = ymax - ymin if w <= 0 or h <= 0: print(f"[skip] {xml_path.stem}: empty bbox after clip") continue cx = xmin + w / 2.0 cy = ymin + h / 2.0 lines.append( f"{class_id} {cx / img_w:.6f} {cy / img_h:.6f} " f"{w / img_w:.6f} {h / img_h:.6f}" ) if not lines: return out_path = out_dir / (xml_path.stem + ".txt") out_path.write_text("\n".join(lines)) # 类名顺序就是 YOLO 的类别 id,顺序一旦确定不要再改 CLASS_NAMES = ["intact", "broken", "missing", "displaced"] XML_DIR = Path("VOC/Annotations") OUT_DIR = Path("YOLO/labels/val") OUT_DIR.mkdir(parents=True, exist_ok=True) for xml_file in sorted(XML_DIR.glob("*.xml")): voc_to_yolo(xml_file, OUT_DIR, CLASS_NAMES)

核心逻辑是:先读<size>拿原图宽高,再遍历<object>取类别名和 bndbox,把坐标转成归一化中心点格式,一条标注写一行,最后写入与 xml 同名的 txt。代码里做了两层防御:一是越界坐标裁回[0, img_w];二是把 xmin 大于 xmax 的脏数据规整回来。不做这两步,训练时你会看到 loss 正常下降,但验证集 mAP 飘忽不定,因为大量归一化结果在 0 到 1 之外的框也进了损失计算。

参数上,class_names列表顺序就是 YOLO 的类别编号,xml 里的<name>必须能对得上,否则脚本会跳 warn。.6f保留 6 位小数是 YOLO 惯例,不推荐改成.2f,小目标框在 1280 长边上的小数误差会被放大成实际像素偏移。

注意:如果同一张图在 xml 和生成的 txt 里目标数量对不上,第一个要查的是空标签,而不是转换脚本。

3.2 归一化坐标的边界坑:0 到 1 之外和 float 精度

第一个坑是越界坐标。很多网上的转换脚本只做“除以图片宽高”,完全不检查坐标是否已经越过图片边界。井盖数据集中,低空俯拍图经常出现标注框的 xmax 比图片实际宽度大几十像素,归一化后变成 1.01。YOLO 训练本身能容忍一点越界,但在 NMS 阶段,中心点落在图像外的框会被当成无效框合并,造成漏检。

我的处理原则是:宁可把越界框裁回边界,也不保留越界值。井盖破损标注的主要区域在画面内,框边缘多出来的部分通常是标注员拖拽失误,裁掉不影响语义。

第二个坑是宽高比极端框。井盖在路面影像里通常是近圆形或方形,但侧视角下会变成扁椭圆。如果某个标注框的宽高比超过 15,大概率是误标了旁边排水沟栅栏或管线井。这类框在归一化后拉伸成窄条,会把检测器对目标尺寸的先验分布带偏,训练出的模型更容易把长条形的路面物体误检成目标。我在转换脚本外再加一道过滤:宽高比超过 15 的框直接丢弃,按 xml 文件名记入日志留给人确认。

第三个坑是 float 精度。归一化时用.6f,1280 像素宽的照片理论误差在 0.0005 像素量级,可接受;但千万别用round(x, 2)或写成整数百分比。训练器读 txt 时把字符串转 float,精度不足的标注会被 yolo 损失函数放大,因为框回归用的是 IoU 联合优化,坐标量化到小数点后两位会让梯度反复震荡,表现为 loss 曲线像锯齿。

第四个坑是 XML 里同时存在多个<size>节点的情况很罕见,但确实遇到过。标注链路里有人用工具重写过 xml,把原图 size 和缩略图 size 都写进了同一文件,解析脚本只取第一个,坐标全错。转换时加一个断言:遍历到的<size>节点必须唯一,否则直接报错,不要静默用第一个。

3.3 最难查的坑:类别顺序错位

这个坑最隐蔽。VOC 转 YOLO 后,txt 每行第一个数字是 class id,不是类名。如果转换脚本里 CLASS_NAMES 的顺序与训练配置 data.yaml 里的 names 顺序不一致,比如转换时“破损”在 0、“完好”在 1,而 data.yaml 写成“完好”在 0、“破损”在 1,模型训练和验证时不会有任何报错,只有最后看预测结果,发现完好井盖被标成破损上报,才会意识到类别错位。

怎么防?我的习惯是不在转换脚本里手工写顺序,而是先从 VOC 的 xml 文件里扫描全量<name>,按类别出现顺序生成一份 classes 映射,再以此为准写转换脚本和 data.yaml。扫描命令就是 2.3 节里那条 grep,跑完再看一眼每个类别的样本量分布,确认没有漏类或混入无关类。

扫描完再做一次冒烟验证:随机抽三张转换后的 txt,对照原图确认坐标框中心点落在井盖上,并人工核对类别编号和业务语义一致。这个动作最多半小时,但能拦住后面好几天的无效训练。我自己的血泪经验是,类别错位往往在训练跑到第 40 轮、准备验收时才暴露,回头清洗标签要花的力气远比一开始核对多得多。

4. 用 YOLOv8 训练这套井盖数据:data.yaml 与关键参数

格式转换完之后,就进入“yolov8训练自己的数据集”的常规流程。我用 YOLOv8 举例,因为工程落地里它最通用,这些参数可以平移到后续版本。

4.1 目录重组与 data.yaml 写法

如果 zip 已经给了 YOLO 侧的 images/labels 目录,那就不需要重组,只需确认 train/val 划分。如果只有 VOC 侧,按上一章转换脚本生成 labels 后,建议目录固定成这个形态:

manhole_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── manhole.yaml

再写训练配置文件:

# manhole.yaml path: /home/user/manhole_dataset # 改成你解压后的绝对路径 train: images/train val: images/val # 类别顺序要和转换脚本里的 CLASS_NAMES 完全一致 names: 0: intact 1: broken 2: missing 3: displaced

这里有几个常见写法差异:一是train项写相对路径时,YOLO 会和path拼接;如果写了绝对路径,就别再让path参与拼接。二是 val 目录必须存在且非空,否则训练会直接报val: not found。三是如果想固定验证集,可以给 train/val 写 txt 文件列表,文件里每行是图片绝对路径,这种写法在多机训练时更好用,但单机随手拷贝数据集时反而容易踩路径坑,我一般只在需要固定划分时才用。

4.2 训练命令与 4 个不要乱调的参数

推荐先用官方预训练权重,不要从零随机初始化。井盖是刚性目标,迁移学习比随机初始化收敛快很多,1377 张的小数据量上尤其明显。

yolo detect train \ data=manhole.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ seed=42 \ device=0

100 epochs、640 输入、16 batch 是基线值。真正要盯的是下面四个参数。

  • imgsz=640:井盖在巡检图中占比差异很大。无人机正射影像里,一个 1280 宽的图井盖可能只有 60 像素宽,缩到 640 输入后只剩 30 像素,小目标几乎学不到东西。这时要么直接imgsz=1280,要么先做切图把原图切成 640 或 896 的小块再训练。我的经验是 imgsz 从 640 提到 1280,mAP@.5:.95 通常能涨 3 到 5 个点,但显存占用接近翻倍,要按卡量力而行。
  • batch=16:显存允许范围内尽量大。1377 张训练集,batch 太小会让 BN 统计不稳定,loss 在 30 epoch 前后反复震荡。8G 显存建议batch=8, imgsz=640起步,不要硬上 batch=16 爆显存。
  • lr0=0.01:用预训练权重时我通常不动。lr 太大会把预训练特征冲掉,太小则 100 轮学不完。如果前 10 轮 loss 完全不动,优先检查标注是不是为空或坐标异常,而不是去调学习率。
  • seed=42:一定要写。训练里有 mosaic、随机 HSV 增强这些随机因素,不锁 seed,同一份数据两次训练 mAP 能差 2% 以上,做参数对比时根本分不清是调参收益还是随机波动。

再说一个很多人爱动但我不建议初学者动的东西:yolo 损失函数里三个权重(box、cls、dfl)的配比。在 1377 张这种量级的数据集上,调损失权重带来的收益远远小于标注噪音带来的干扰;我见过的大多数反复调参,最后都不如把训练集里几十张错标图抽出来重标一遍有效。

其余参数像 workers、cache、patience 属于运行环境参数。cache=True把图片预加载到内存,能明显加快小数据集训练,但内存不足会直接卡死;patience=30配合早停,避免无效长训。

4.3 验证与推理:best.pt 到手后先看置信度分布

训练结束,我一般不会直接看 train 曲线拍板,而是立刻跑一次评估和批量推理:

yolo val model=runs/detect/train/weights/best.pt \ data=manhole.yaml \ imgsz=640 \ batch=8 yolo predict model=runs/detect/train/weights/best.pt \ source=test_images/ \ save_txt=True \ save_conf=True

val 会输出每类的 precision、recall、mAP50、mAP50-95。对井盖四分类,重点看missing类的 recall。丢失类在数据里往往样本少,模型学习时偏向把目标判成频度更高的破损;如果 recall 低于 0.8,说明漏了不少井洞,这类漏报在实际巡检里是要出事的。

predict 时我会开save_conf=True,把置信度一并存进 txt,再写个小脚本统计“各类别在不同置信度阈值下的检出数”,画一条置信度-召回曲线。这样做不是为了严谨评估,而是为了判断上线阈值定在 0.25、0.45 还是 0.6 合适。井盖检测的误报代价和漏报代价不对称,阈值不能只看 mAP 最大的位置。

5. 井盖数据集训练和推理中的 5 条避坑记录:现象、原因、解决

以下五条是真实街道影像上反复踩过的账,按“现象、原因、解决”的顺序写。

5.1 训练卡在 Scanning labels,或起步后 Samples 为 0

现象:输入训练命令后,日志停在Scanning labels很久,或者显示 Sample 数是 0,一个 epoch 都走不完。

原因:标签文件和图片文件没有同名对应,或者标签内容是空文件。常见于 zip 解压后路径被截断,比如labels/train/001.jpg.txt这类嵌套怪名;另一个常见原因是 VOC 转 YOLO 时把00002.xml转成了00002_jpg.txt,而图片叫00002.jpg。

解决:写一个两分钟的自查脚本。

cd manhole_dataset for f in labels/train/*.txt; do base="${f%.txt}" img="images/train/$(basename "$base").jpg" if [ ! -f "$img" ]; then echo "MISSING IMG: $img" fi if [ ! -s "$f" ]; then echo "EMPTY LABEL: $f" fi done

先处理 MISSING IMG,说明命名对不上;再处理 EMPTY LABEL。背景图保留本身没问题,但如果是大量文件为空,说明转换脚本在类别过滤时把目标全部滤掉了,要回头查类别名大小写。还有一种情况是图像侧是 HEIC 或 png 后缀,标签侧按 jpg 生成,同样会报 MISSING IMG;我的处理是先把图像统一转成 jpg,再做文件名对齐,不让后缀问题混进训练链路。

5.2 完好和破损互相误判:混淆矩阵主对角线外面那两条最刺眼

现象:val 的 mAP 不低,打开混淆矩阵发现intact有 20% 被预测成broken,broken也有 15% 被预测成intact。

原因:这大概率不是模型能力问题,而是标注口径不一致。不同标注员对“破损”的定义有偏差:一条浅裂缝算不算破损?井盖边角略微变形算不算?同一个人在不同批次标也会漂移。

解决:把训练集中所有broken和intact的样本各抽 50 张出来看,通常能明显看出两派标注风格。我的处理是挑出模棱两可的样本做一次标签复核,或者更省事:先合并成二分类“需维修 / 不需维修”,把问题压成单决策边界,等后续有更精细的标注补充再升级四分类。井盖检测落到真实运维,第一优先级是“要不要派人去现场”,类别分得太细但噪声大,反而没有实用价值。

5.3 丢失类在夜间和积水路面疯狂误报

现象:白天晴天验证集 mAP 好看,一旦换到夜间路灯场景或雨后潮湿路面,大量井盖周围的深色区域被误判成“丢失”,巡检视频里出现一连串假报警。

原因:丢失类的本质特征是“井口露出深色空洞”,但夜间井盖周围阴影、路面积水倒影、沥青修补块,局部纹理同样是深色区域,单帧局部特征区分不了。这属于场景和类别语义的冲突,不是简单增强能根治的。

解决:两个层面。训练层面,把夜间、雨天、逆光的井盖图像并入数据集,并对丢失类做针对性增强:随机降低亮度、加高斯噪声、轻微运动模糊,让模型不再依赖“很黑”这一条线索。推理层面,不要单帧定论。巡检车或无人机经过同一井盖能拍到多帧,做连续帧投票——同一位置连续 3 帧以上检出丢失且中心点相对位移稳定,才触发报警。这个逻辑能把误报率直接砍掉一半以上。

5.4 loss 正常下降,mAP50 也不错,但 mAP50-95 一直上不去

现象:训练 loss 曲线平滑下降,mAP50 到 0.85,可 mAP50-95 卡在 0.45 左右,怎么调都涨不动。

原因:mAP50-95 对框的位置精度和 IoU 重叠非常敏感。井盖小目标在原图 1280 里可能只有 40 像素,输入缩到 640 后只剩 20 像素,框哪怕偏 3 个像素,IoU 就从 0.7 掉到 0.5。这不是模型收敛问题,是“输入分辨率把小目标细节丢了”。

解决:优先把imgsz提到 1280 重新训练,显存不够就做切图训练。切图做法是把原图切成 640×640 patch,同时把落在 patch 边缘被截断的目标过滤或延边补齐。这一步对井盖这种分布较均匀的路面目标特别有效。如果显存实在吃紧,换 yolov8s 而不是更小的 n,小模型在小目标上反而更容易欠拟合。

5.5 同一份数据两次训练结果差两个点以上,复现不了

现象:完全相同的数据和命令,昨天跑 mAP50 0.87,今天重跑只有 0.84;换个机器差别更大。初看像玄学,其实是随机性没锁住。

原因:YOLO 训练默认开启 mosaic、随机旋转、HSV 增强,这些变换的随机种子没有固定,验证集划分也可能重新随机,两个扰动叠加,几点的波动很正常。

解决:命令里固定seed=42,同时把验证集固定下来。如果 data.yaml 只给了 train/val 目录,而每次启动内部重新划分,就不如自己生成稳定的 train.txt 和 val.txt 两个清单,让每次训练面对同一批验证图。再配合随机增强里的 seed,基本能把两次训练的 mAP 差压到 1 个点以内。做完这一步再谈调参,对比才有意义。

6. 进阶:用连续帧与 F1 把模型从“能跑”变成“能验收”

井盖检测最终不是看一张图出几个框,而是看能不能形成一条可验收的巡检结论。我提两个进阶用法。

第一个是把评估指标从 mAP 切到 F1 和漏报率。市政项目里,业主更关心“丢失类有没有漏”“完好类误报了几次”。我习惯在 val 之后对missing类单独算 recall,在某个置信度阈值下跑完整条巡检片段,统计每公里的误报数与漏报数。这几年很多项目都要求巡检系统输出精确率、召回率报告,只交一个 mAP 数字不够验收。

第二个是连续帧的时序确认。用一个很轻的“位置网格加计数”逻辑就能做,不需要上跟踪算法:

from collections import defaultdict # 简化的网格计时逻辑:同一网格连续命中才算一次告警 counter = defaultdict(int) threshold = 3 for frame_id, dets in enumerate(frame_sorted_detections): for det in dets: if det.conf < 0.45: continue # 按 100 像素网格粗分坐标,先聚合再计数 grid = (det.cls_id, round(det.cx / 100), round(det.cy / 100)) counter[grid] += 1 if len(dets) == 0: # 该帧没有检测时对所有计数减半,避免长时间累积误报 for k in list(counter.keys()): counter[k] //= 2 if counter[k] == 0: del counter[k] alarms = {k: v for k, v in counter.items() if v >= threshold}

逻辑不依赖复杂跟踪,只要求帧间井盖位置相对稳定,很适合巡检车匀速直线行驶的场景。参数上,conf 阈值 0.45 需要根据第 4 章那条置信度-召回曲线回调,threshold=3 对应“连续三帧确认”。

至于“yolo实例分割”方向的扩展:如果项目要计算破损面积或井盖尺寸,bbox 检测只能给位置,面积测量必须换分割模型。做法是把 VOC 的 bndbox 坐标转成 polygon,再喂给 yolo-seg 训练,注意原本只有 bbox 的数据集不能直接训分割。另一个可考虑方向是把bdd100这类道路场景数据作为补充负样本,用来压掉夜间误报,但补充时注意别把井盖数据本身的场景分布冲散。

最后说一个我的习惯:拿到任何 zip 数据集,先花固定半小时跑完第 2 章的五个校验,再转换、再训练;每一批误报坏例都丢进一个 bad case 文件夹,下个版本训练时抽出来复盘。类别错位白跑一周末的事我不想再来第二次,这套工序不炫技,但能把井盖检测做成每天能交活的系统。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/4 4:29:09

PIC32+MRAM工业现场数据可靠存储方案与SPI实现要点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 4:26:16

GPS基本原理与Matlab仿真:从星历计算到位置解算全解析

1. 这本书为什么值得啃&#xff1a;先说我的判断收到一个很有意思的标题&#xff1a;“gps matlab 书&#xff0c;《GPS基本原理及其Matlab仿真》杨俊.pdf”。这不是一个普通的资源文件名&#xff0c;背后藏着一整条学习路径。我当年啃GPS算法的时候&#xff0c;市面上能找到的…

作者头像 李华
网站建设 2026/10/4 4:25:50

WebGL着色器原理与GLSL实战:从顶点到片元的完整解析

写WebGL绕不开着色器。哪怕你已经会用gl.drawArrays画出三角形&#xff0c;只要想换颜色、做扭曲、加光照&#xff0c;立刻会发现卡在一段看不懂的字符串代码上——没错&#xff0c;那就是着色器。这套基础教程前两篇我们把初始化流程和绘制管线铺完了&#xff0c;这一篇专门聊…

作者头像 李华
网站建设 2026/10/4 4:25:01

基于WebSocket的跨平台远程桌面工具:协议、编码与安全

简介&#xff1a;一套基于WebSocket的跨平台私人远程桌面工具源码&#xff0c;面向计算机相关专业毕业设计及远程控制方向学习者。系统以Spring Boot为后端框架&#xff0c;整合Java AWT与WebSocket协议&#xff0c;实现鼠标键盘模拟、远程DOS命令执行、远程关机与重启&#xf…

作者头像 李华
网站建设 2026/10/4 4:24:50

SpringBoot股票模拟交易系统毕设:交易链路与资金核算实战

先说个比较现实的事儿&#xff1a;每年计算机相关专业做毕设&#xff0c;光是"股票类系统"这个方向&#xff0c;十个组里至少有三四个会碰。但绝大多数人交上来的东西&#xff0c;要么是前端换个皮、后端就几个CRUD&#xff0c;要么是数据库表建了一堆&#xff0c;一…

作者头像 李华
网站建设 2026/10/4 4:22:52

AI Agent 接入 Redis 缓存实战:高并发架构设计与性能优化

1. AI Agent 接入 Redis 缓存&#xff1a;从零搭建到扛住并发的实战拆解AI Agent 这个方向最近一年有多热&#xff0c;不用我多说。但真正上手搭过 Agent 的人都知道&#xff0c;一个能跑起来的 Demo 和一个能扛住真实流量的系统之间&#xff0c;差的不只是模型能力&#xff0c…

作者头像 李华