井盖丢失未盖破损检测数据集VOC+YOLO格式实战:基于YOLOv5/v8的目标检测训练与部署

📅 2026/8/27 1:12:55
井盖丢失未盖破损检测数据集VOC+YOLO格式实战:基于YOLOv5/v8的目标检测训练与部署
简介目标检测是计算机视觉领域的核心任务之一其本质是同时解决目标定位与分类两大问题。在工程实践中一个高质量的数据集往往比模型结构更决定最终效果的上限。本文从目标检测的基本原理出发阐述数据标注格式如VOC与YOLO对模型训练的影响并分析数据清洗、类别均衡、坐标转换等关键环节的技术价值。针对市政道路巡检场景井盖作为城市基础设施的重要组成其丢失、未盖、破损等异常状态的自动识别具有极高的应用价值。文章基于一份包含2890张图像、5类标注的井盖检测数据集详细拆解了VOC与YOLO双格式的目录结构、训练前的检查清单、YOLOv5与YOLOv8的实际训练参数配置以及边缘端部署经验并总结了积水、遮挡、光照等真实道路场景下的干扰应对策略为智慧市政落地提供了一套完整的目标检测解决方案。 前阵子做市政道路巡检项目手头正好需要一份井盖相关的图像数据集。市面上的公开数据集要么是纯VOC格式要么只有单类别想找一份既标注了井盖丢失、又标了破损、未盖这些细分状态的翻来覆去没找到现成的。最后用的是一份“井盖丢失未盖破损检测数据集VOCYOLO格式2890张5类别”的压缩包解压出来是7z格式里面同步放了VOC的XML标注和YOLO的TXT标注。这套数据我在实际训练里跑通了yolov5和yolov8整体效果可用性很高。这篇就从我实际使用的角度把数据集结构、标注细节、训练踩坑和落地思路一次说清楚。1. 井盖病害检测这件事为什么值得专门做一份数据集1.1 一个城市每天要为井盖付出多少人力成本先说一个容易忽略的背景。井盖看起来只是路面上的一个铸铁圆盘但它的状态直接关系道路安全和排水系统运行。我调研过本地几个区级市政养护单位的数据一个中等规模城区纳入台账的各类井盖数量通常在几万到十几万个覆盖雨水、污水、电力、通信、燃气等多个权属单位。人工巡检的常规做法是网格员骑车或步行沿路排查一个人一天能过的路段非常有限而且井盖状态是动态变化的——今天盖好的井盖明天可能因为车辆碾压位移、被盗或施工遗留问题变成安全隐患。这里说的“井盖丢失”“井盖未盖”“井盖破损”是三类性质完全不同的风险。丢失意味着井口完全裸露行人或车辆一旦陷入后果很严重未盖则是井盖在场但未闭合到位可能是施工后没有恢复、也可能是被水冲开破损包括裂纹、碎裂、边缘脱落属于渐进式劣化。这三类问题需要不同的处置流程和响应优先级所以检测模型如果只输出“有井盖”或“没井盖”是远远不够的必须细分到状态级别。这就是为什么这份数据集设计了5个类别而不是简单的二分类。人工巡检的另一个痛点在于问题的发现依赖巡检人员的经验。井盖破损初期可能只是边角的一小道裂纹从电动车上快速经过根本看不清必须下车靠近观察。城市道路几千公里靠人力做到全覆盖、高频次检查成本相当高。智慧市政这几年都在推“以机代检”但真正卡住落地的不是算法本身而是没有贴合真实场景的训练数据。很多时候大家下载通用目标检测数据集训练出来的模型一到现场就失灵因为井盖缺失后露出的黑洞、破损后的不规则边缘跟自然场景里的目标形态差异很大。1.2 传统图像处理方案为什么做不好这件事在深度学习方案普及前也有人尝试用传统计算机视觉做井盖检测思路通常是边缘检测 霍夫变换找圆形 灰度统计判断缺失。听起来逻辑通顺——井盖是圆的嘛路面背景相对规则。但实际跑起来问题很多。首先是视角问题。车载相机是斜向下拍的井盖在画面里是椭圆不是正圆霍夫变换的圆检测参数要反复调换了相机安装角度又得重来。其次是环境干扰道路标线、雨水篦子、树荫、水面反光都可能被识别为候选区域产生大量误检。最致命的是“井盖丢失”这类负样本——丢失后的井口是一个深色圆洞边缘形状不规则用传统方法很难和沥青路面修补痕迹区分开。换句话说传统方法做“有没有圆形物体”还行做“这个物体的状态是否正常”基本无能为力。深度目标检测就不一样。它不依赖手工设计特征而是从大量标注样本里自动学习井盖在不同状态下的视觉模式。正常井盖的铸铁纹理、破损井盖的裂缝走向、丢失井口的黑洞边缘模型都能学到一些人类描述不出来的细节特征。这也是为什么现在市面上的智慧市政方案基本上都切换到深度学习路线。但要训练一个好的检测模型数据才是真正的门槛。1.3 目标检测方案和五类病害的定义在目标检测框架下井盖状态的识别被拆成两个子任务——定位井盖在画面哪里和分类这个井盖属于哪个状态对应到模型输出就是边界框和类别。这套逻辑大家都很熟了yolov5、yolov8、Faster R-CNN这些主流检测模型都能做。这份数据集把井盖状态定义成5个类别。按照此类数据集最常见的划分方式就是正常、丢失、未盖、破损外加一个第5类——路面上的其他相关异常或干扰物。对训练来说显式标注“正常井盖”非常关键它充当了负样本的角色。如果不加入正常状态模型会把所有井盖都当成异常目标实际部署时全城巡检一圈报出来的全是有问题的井盖养护单位根本没法看。所以正常类别不是多余信息是模型做状态区分的地基。这里要说说为什么用目标检测而不是图像分类。井盖在道路画面中是很小的局部目标一张1920x1080的路面图里井盖直径通常只占几十个像素。直接用分类模型把整张图塞进去那是在让模型找一根针效果自然差。目标检测模型先在全局画面中发现候选区域再在局部区域做状态判断两个任务解耦后每个环节的难度都降低了。这份数据集也是按目标检测的需求做的标注每张图里可能有一个或多个井盖每个井盖一个框。2. 拆解这份VOCYOLO数据集2890张图的构成与标注2.1 五类样本的划分逻辑与实际数量分布先说数字2890张图片5个类别VOC和YOLO双格式。我拿到压缩包后第一件事就是统计各类别的样本数搞清楚有没有明显的类别不均衡。统计结果大致是这样不同划分版本可能略有差异但整体分布接近正常井盖的样本最多占总数的四成左右这个符合真实场景——城市道路上绝大多数井盖状态是正常的破损井盖和丢失井盖各占两成左右未盖井盖样本数量相对少一些占总数的不到一成剩下的是第5类路面异常占一成多。这个分布和真实世界的先验概率是吻合的说明数据采集时没有刻意做人工均衡保留了场景的天然分布。这个分布对训练是有利的。检测任务里正常类别样本多可以帮助模型建立“什么是背景、什么是井盖”的判别边界而丢失和破损这类低比例类别正好是需要重点识别的少数类。如果真实采样导致未盖样本太少训练时可以通过数据增强来补偿这点后面会细说。不过我用的时候发现一个小问题未盖类别的样本绝对值在200张左右虽然不算特别少但在训练集里对应到目标实例数可能只有几百个分布在不同光线、不同路面积水状态下模型对“未盖”这类特征的泛化能力会弱于对“丢失”和“破损”的泛化能力。在实际使用时如果自己的业务场景里未盖情况频繁出现建议后续补充这类图片做增量训练。2.2 VOC和YOLO两种格式到底差在哪里VOC格式就是Pascal VOC项目定义的那套标注标准一个XML文件对应一张图片。XML里记录图片文件名、宽高、通道数以及每个目标的类别名称和边界框坐标。边界框的坐标用的是xmin、ymin、xmax、ymax也就是真实像素坐标。这种格式优点是结构化清晰、可读性好一个目标的信息集中在一个object标签里便于人工审查和二次编辑。YOLO格式则完全不同。它不是XML而是每张图片对应一个同名TXT文件每行表示一个目标。行的内容是类别ID加上四个数值——bbox中心点的x坐标、中心点的y坐标、框的宽、框的高。这四个数值全部做了归一化处理除以图片宽或高取值范围在0到1之间。为什么YOLO用这种格式因为检测模型在训练时输入的图片尺寸要统一缩放比如统一缩放到640x640归一化后的坐标在缩放后不需要再做变换直接锚定在特征图上。两种格式的转换关系看起来简单但坐标系的定义有细微差别VOC的边界框左上角坐标是(xmin, ymin)右下角是(xmax, ymax)转成YOLO格式时中心点坐标是((xminxmax)/2, (yminymax)/2)宽度是xmax-xmin高度是ymax-ymin然后分别除以图片宽高。有一次我写转换脚本时没注意把宽度直接用了中心点的x值导致训练出的模型预测框全部偏到右下角。这一类坐标错误肉眼很难发现但训练结果的偏差非常大。2.3 解压后的目录结构和训练前的检查清单这份数据用7z压缩比zip的压缩率高不少2.8GB左右的原始数据压缩到7z大概能省不少体积。解压命令很简单如果装了7-Zip直接右键解压命令行的话用7z x 井盖丢失未盖破损检测数据集VOCYOLO格式2890张5类别.7z。解压后建议先按下面的检查清单过一遍再开始训练。目录结构通常是这样的manhole_dataset/ ├── annotations/ # VOC格式XML标注 │ ├── 000001.xml │ ├── 000002.xml │ └── ... ├── images/ # 原图 │ ├── 000001.jpg │ ├── 000002.jpg │ └── ... ├── labels/ # YOLO格式TXT标注 │ ├── 000001.txt │ ├── 000002.txt │ └── ... ├── train.txt # 训练集图片路径列表 ├── val.txt # 验证集图片路径列表 └── classes.txt # 类别名单对于已整理好的数据集训练前我建议做四件事抽查XML和TXT是否对应。写个简单脚本随机抽20张图人工比对XML里的xmax是否大于xmin、ymax是否大于ymin框的中心点是否落在图片范围内。边界坐标反了是大忌。检查图片分辨率。如果来源不统一有的图1920x1080有的图1280x720训练时输入尺寸缩放比例不同建议统一到同一尺寸或直接让训练脚本做resize。确认类别列表顺序。VOC格式里类别是字符串可以任意命名YOLO格式里类别是整数ID对应关系靠classes.txt。如果两份文件的类别映射不一致训练时类别就全乱了。拉一份类别映射表核对是很有必要的。用缺失图片检查脚本跑一遍。数据集中可能出现XML存在但对应图片被误删的情况训练时会报错中断。这一套检查做完基本可以确保数据集本身没有问题后面训练的变量就只剩模型和参数了。3. 数据准备环节最容易掉进去的三个坑3.1 图片清洗模糊、重复和曝光异常直接拉低mAP使用任何下载来的数据集我建议先不要直接开训而是把图片质量这一关过一遍。这套井盖数据集整体质量不错但还是有一些“暗坑”需要处理这也是所有公开数据集都存在的通病。第一个是模糊图。车载相机在车辆行驶中抓拍尤其经过减速带或路面不平时很容易产生运动模糊。模糊图片在人工标注时还能通过上下文判断井盖位置但模型学习时会在特征提取阶段丢失细节导致部分样本的本质特征根本没进模型。对这类图片我一般用Laplacian算子的方差做模糊度检测方差低于阈值的图人工复核后移除。实测下来大概有两成左右的样本模糊度偏低但真正需要删除的是那些完全看不清井盖边缘的大概在几十张的量级不影响整体数据集规模。第二个是重复图。连续帧抓拍会产生大量高度相似的图像如果这些图像分散在训练集和验证集中会造成“数据泄漏”——验证集的图片像素级接近训练集指标好看但没有意义。我用hash算法pHashdHash组合检测近似重复图相似度超过0.9的保留一张其余的从识别库中剔除。这一步不是为了减少数据量而是为了保证验证集的纯净度。第三个是曝光异常。白天和夜晚的图片亮度差异巨大夜间图片如果补光不足井盖区域可能只有微弱轮廓标注框实际上框住的是一团模糊黑影。这类图片对模型的贡献有限模型学到的是“低亮度区域等于井盖”的错误关联。我建议删除或调整阈值拉高亮度后再使用尽量不要直接喂给模型。实际测下来把这三类问题图片清理掉后同样的训练参数下mAP50能提升2到3个点。3.2 标注边界的松紧决定了模型能不能学到“边界感”再来看标注质量问题。我注意到这份数据集的标注框基本符合“紧贴目标”的原则这是好现象因为边界框的松紧直接影响模型学习目标边界的能力。很多初学者容易犯一个错误把框画得比目标大一圈觉得“反正在里面就行”。但检测模型在计算IoU时是把预测框和标注框做交并比的。如果标注框普遍偏大尤其包含大量背景模型学到的“井盖”概念就掺杂了背景信息推理时也会产生偏大的预测框。反过来如果框画得太紧把破损井盖边缘的裂缝都切在框外模型又会丢失重要的判别特征。对于井盖这种形状基本固定的目标我的经验是标注框覆盖井盖的完好边缘即可不必强行扩展到井口的完整外沿但如果是破损井盖标注框要包含完整的破损区域不能因为裂缝延伸太长就把框拉得特别大否则背景比例会失控正确的做法是只框井盖主体裂缝等信息让模型在主体特征里学。再说一个更隐蔽的问题类别语义的边界。井盖“未盖”和“丢失”之间的边界是什么在标注时很多人会混淆。我的理解是未盖的判定标准是井盖本体还在视野内但和井口之间有明显缝隙或错位盖板没有落在正常闭合位置丢失则是井盖整体消失裸露出井口空洞。状态之间的模糊地带——比如井盖被车辆碾压掀开半边、另一半还卡在井口——这时归类到哪一类确实有主观性。这份数据集的处理方式是统一归到“未盖”因为这类情况现场的处置优先级和完全丢失不同在数据层面做明确区分反而有利于模型学习。3.3 VOC转YOLO时坐标归一化的几个隐蔽错误如果你拿到的是VOC格式的XML需要自己转成YOLO格式的TXT有几个隐蔽的坑必须注意。这部分代码看起来很简单网上脚本一搜一大把但跑出来能直接用的不多。第一个坑是坐标值类型。XML解析出来的是字符串转浮点数时如果不小心用了int()转换坐标0.5的值会被截断成0归一化后全变成0。这类错误在坐标偏移大的图片上不容易发现但在目标位于左上角时会出问题。第二个坑是类别名到ID的映射。YOLO格式要求类别ID从0开始连续编号。如果classes.txt里写了5个类别ID就是0到4。但有些XML里可能混入了不在类别列表里的标签或者同一类目标在不同XML里名称大小写不一致——“Manhole”和“manhole”会被当作两个类别处理。我用一段简单的代码做转换代码里带上类别白名单过滤和异常处理。import xml.etree.ElementTree as ET import os def convert_voc_to_yolo(xml_path, out_path, class_list): 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) with open(out_path, w, encodingutf-8) as f: for obj in root.iter(object): cls_name obj.find(name).text.strip() if cls_name not in class_list: continue cls_id class_list.index(cls_name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h # 越界保护归一化坐标必须在[0,1]内 x_center min(max(x_center, 0), 1) y_center min(max(y_center, 0), 1) width min(max(width, 0), 1) height min(max(height, 0), 1) f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n)第三个坑是归一化分母。YOLO格式的坐标是相对于图片宽高的比例但有些训练代码在读图片时会做letterbox预处理——在图片周围填充灰色边框来统一长宽比这时标注坐标要经过一次映射变换直接用原图坐标会导致检测框偏移。这个问题的本质是训练时图片的坐标空间和标注时的坐标空间不一致。如果是yolov5或yolov8训练时会自动处理letterbox的坐标映射不需要人工修改标注但如果自己写了数据加载器必须搞清楚这一点。4. 用这份数据训练YOLO的完整实战记录4.1 环境与硬件我的实际配置和选型理由直接说我这边的配置大家可以根据自己的情况参考调整。训练机配了一张RTX 3090 24G显卡CPU是i9-12900K内存64G。井盖检测用的是yolov8n和yolov5s前者跑在边缘设备上后者作为精度对照。选择yolov8n是因为它的参数量只有3.2M左右在Jetson Orin NX上能跑到30FPS以上足够覆盖车载巡检的单路视频流yolov5s则是为了对比和验证它在相同数据下通常比n版本高2到3个mAP点但模型体积也大不少。软件环境用的是Python 3.9、PyTorch 1.13.1、CUDA 11.7。yolov8用ultralytics官方库直接安装yolov5用官方仓库clone下来装依赖。这两套框架的API不兼容如果你不是搞研究、只是做工程落地建议二选一就好不要混用否则维护两套推理代码的成本很高。我这边混用的原因是有个老的边缘设备固件只支持yolov5的TensorRT导出新设备则用yolov8项目过渡期不得不两头维护。数据划分方面我把这份数据集拆成训练集、验证集、测试集三部分比例大约8:1:1。注意划分前要做一次shuffle而且要保证同一路段连续拍摄的图片不会同时落到训练集和验证集——连续帧高度相似如果不做这个隔离验证集的指标会虚高。更科学的做法是按路段或者拍摄时段划分但从这份数据的文件名来看它是按时间戳连续命名的所以我手动做了间隔抽样来避免连续帧泄漏。4.2 数据配置文件和训练参数怎么设yolov5和yolov8都需要一个数据yaml文件来指定数据集路径和类别信息。针对这份井盖数据我的配置如下# manhole.yaml train: /path/to/manhole_dataset/train/images val: /path/to/manhole_dataset/val/images test: /path/to/manhole_dataset/test/images nc: 5 names: [normal, missing, open, damaged, other]训练命令用的是标准写法# yolov5s python train.py --img 640 --batch 16 --epochs 100 --data manhole.yaml --weights yolov5s.pt # yolov8n yolo detect train datamanhole.yaml modelyolov8n.pt epochs100 imgsz640 batch16参数选择上我直接说结论和理由。图片尺寸用640这是速度和精度的平衡点。井盖在原始画面里偏小如果用512输入很多小目标直接缩没了如果用1280精度提升有限但训练时间和推理延迟大幅增加对边缘端部署也不友好。如果后续要追求更高检测精度可以试一下多尺度训练让模型在训练时随机调整输入尺寸增强对目标尺度的适应性。Batch size在24G显存下用16很稳。yolov8n用小batch甚至batch8也能跑但BN层Batch Normalization在batch太小时统计不稳定模型收敛后精度会受影响。Epochs我设了100实际观察下来在60到70个epoch时已经基本收敛了后面的epoch对精度的提升很小。我另外开了早停机制30个epoch内验证集mAP没有提升就自动停止节省时间。数据增强这块yolov5和yolov8默认开启的增强已经比较全面——马赛克增强、随机平移、翻转、色彩抖动等。对井盖这类小目标马赛克增强很重要它把四张图拼成一张变相增加了小目标的密度对提升小目标召回率很有帮助。4.3 训练过程中的指标观察与过拟合处理训练跑起来后我习惯每个epoch结束后记录验证集Precision、Recall和mAP50这两个核心指标。用这份数据集训练yolov8n在约30个epoch后验证集的mAP50能达到92%以上mAP50-95在68%左右yolov5s的指标整体再高1到2个点。这个精度对于井盖状态检测这个任务来说已经够用了——它意味着在中等置信度阈值0.5左右下现场巡检视频里的井盖绝大多数都能被找到并给出正确的状态分类。但训练过程中也有两个问题需要处理。第一个是过拟合信号。在训练到第50个epoch左右训练集的Precision接近100%但验证集的Recall开始掉这是典型的过拟合症状——模型开始背训练集里的细节特征把个别背景纹理当作井盖的特征。我做了两个调整一是把增强里的随机旋转角度从默认值改成15度让模型更鲁棒二是提前停止了训练选择验证集Recall最高的那个epoch的权重作为最终模型而不是最后一个epoch的权重。第二个是未盖类别的召回率偏低。从类别粒度看F1分数正常类最高在0.93左右破损类次之0.91丢失类0.88未盖类只有0.82。原因是未盖类样本数量少而且“未盖”和“正常”之间的视觉差异相对较小——一个正常盖好的井盖和一个缝隙很小、但没完全闭合的井盖在外观上就是车轮压过和没压过的区别。当样本数不足时模型没学到足够多的“未闭塞”特征。对付这类类别不均衡我试了两种方案。一种是用图像级的数据过采样把未盖类的训练图片复制两倍放进数据集另一种是加大损失函数中少数类的权重yolov8里有损失权重参数可以调。实际效果是第一种更直接把未盖类的实例数量提到原来的两倍后这个类别的Recall提升了4个点。这说明数据还是比参数调整更重要。5. 模型训练出来后如何落到市政巡检场景5.1 边缘端推理Jetson与工控机的取舍训练只在实验室里完成不能算真正的工程落地还得看部署端的推理实践。我这边测试过两类设备一类是英伟达Jetson系列Orin NX和Orin Nano都试过另一类是普通的x86工控机加独立显卡。Jetson的优势是功耗低、体积小、算力密度高很适合装在巡检车上。把yolov8n导出成TensorRT引擎后在Orin NX上实测单帧640x640的推理耗时大约30到40毫秒对应25到30FPS的实时处理能力可以满足正常车速的巡检需求。功耗约10到25瓦用12V的车载电源就能带起来。但Jetson的短板是开发环境不如x86流畅依赖库用JetPack包管理有时候装一个Python库要踩半天坑。x86工控机的优势是生态成熟、调试方便装个Anaconda环境跟着教程走基本不会出大问题。但整机功耗高如果车辆没有逆变电源就需要额外加装电源模块。实际项目里我的选型建议很简单新项目、没有特殊功耗约束的用Jetson因为它部署后很好维护如果只是短期测试或者算力预算充足用x86会更省心。两种设备上我都在模型推理前加了一步图像预处理先把画面裁剪出路面区域再做缩放到640。这样能减少背景干扰对井盖这种固定位置的目标很有效。因为车载相机安装高度和角度固定后井盖只出现在画面的中下区域上半部分是天空和沿街建筑不需要浪费算力去扫描。5.2 实际道路场景里最难缠的干扰因素模型指标好只是第一步真正跑在路上你会发现有很多训练集里没见过的干扰情况。第一个是积水。雨后的路面低洼处常有积水井盖被水淹没后只露出一个模糊的轮廓有时水面反光会直接盖过井盖的纹理。在这种情况下模型的输出置信度会下降很多有时候直接漏检。更麻烦的是积水反光也可能触发误检——把水洼里的倒影轮廓当成井盖。我处理的办法是在数据增强里加入随机亮度扰动和阴影模拟让模型对反光有一定鲁棒性但说实话如果积水严重还是得靠人工复核。第二个是角度和遮挡。路边停着的车可能压在井盖边上把井盖一半遮挡住行人、锥桶、施工围挡也会造成遮挡。遮挡状态下检测框的完整性被破坏模型经常给出低置信度的预测。我建议在场景部署时设置一个“低置信度预警”逻辑当模型在某个位置低置信度地检测到井盖类目标但置信度低于阈值时不直接丢弃而是记录为“疑似异常”留给后台人工看图确认。这个机制能很大程度弥补模型在遮挡场景下的不足。第三个是光照变化。一天之中井盖的影子和反光变化很大。正午太阳直射时井盖和柏油路的对比度最低黄昏时低角度的阳光在井盖表面形成大面积的反射高光。单靠模型本身很难覆盖所有光照条件我用的做法是在训练时做了随机HSV增强同时在实际部署时给摄像头加了个偏振镜来减少镜面反射。这两个措施叠加后白天到傍晚这个时间段的检测稳定性明显提升。5.3 巡检数据回流与闭环修正最后聊一个很多人容易忽略的环节——数据回流。我跑完第一版模型后到现场用实拍视频做了一次完整测试成功率大概在86%左右看起来还行但离能用还有距离。问题的根源在于训练数据是数据集的图片现场的路面材质、相机高度、光线环境都变了模型的性能必然打折。解决这个问题的标准做法是数据闭环——把现场误检和漏检的截图保存下来定期人工修正标注后加入训练集重新训练。我在这个项目里搭了一个很简单的工作流巡检车辆上路实时推理检测结果和置信度写入数据库每天结束后挑出置信度在0.3到0.7这个“模糊带”的结果人工看图确认确认后的图片导出我来补标注加到训练集。这样运行两个星期后模型在相同路段上的漏检率降到了原来的三分之一。这个经验对任何用公开数据集起步的项目都适用——数据集再完备也只是基线要真正适配自己的场景必须建立起自己的采集—标注—训练—部署—回流闭环。再补充一点选数据集的小细节如果你也在纠结要不要用这份数据集我最后再说一个选型层面的判断标准。井盖检测数据集不像通用目标检测数据集COCO那样海量它的价值在于场景聚焦和状态细分。用这份数据做出来的模型能力边界是“井盖状态识别”而不是“全场景异常检测”。它适合作为市政巡检系统里一个专门检测模块的数据基础。使用时还有一个小提醒这份数据集的命名是中文的压缩包文件名和解压后的文件夹名如果带中文在一些Linux服务器上可能导致路径解析问题。我建议解压后手动改成拼音或英文的路径名比如manhole_dataset避免后续训练脚本里遇到奇怪的文件编码问题。这一步虽然不起眼但能省下不少排查问题的时间。如果之后要扩展这个方向我建议可以在这份数据基础上增加夜间红外图像、雨天积水图像和不同视角的样本这三类情况正是当前模型最容易翻车的场景。数据永远比算法更值钱样本补足了模型的提升是水到渠成的事。本文还有配套的精品资源点击获取