ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

玻璃清洁状态检测数据集:基于YOLO标注格式的完整构建与训练指南

玻璃清洁状态检测数据集:基于YOLO标注格式的完整构建与训练指南 做玻璃清洁状态检测这件事最早我是被一个商场的需求推着上手的。商场的玻璃护栏、自动扶梯两侧的玻璃围挡、临街橱窗面积大、人流量多保洁人员排班全靠经验经常出现“该洗的地方没洗刚洗完的地方又被摸花”的情况。后来发现要落地一个能自动识别玻璃脏不脏的模型卡在第一关的不是算法而是数据——网上公开的玻璃污渍数据集基本找不到自己拍又不知道该怎么标才规范。所以就有了这个第069期的内容一套基于YOLO标注格式的玻璃清洁状态检测数据集免费分享出来专门解决“有没有、脏不脏、脏在哪”这三个核心问题。这套数据和普通的目标检测数据集不太一样它面对的目标不是人、车、猫狗而是半透明、强反光、边界模糊的玻璃表面。再加上“清洁状态”是一个连续变化的概念不是简单的有或无标注时稍不严谨模型训练出来就很容易误判。如果你正准备做智慧环卫、商业综合体智能巡检、清洁机器人或者是玻璃幕墙养护方向的视觉项目这套数据集可以帮你省下大量的采集和标注时间。本文会从数据集的构建思路、YOLO格式的细节、标注规范、训练实操到踩坑记录完整拆一遍希望能给后续做类似项目的朋友一些参考。1. 项目背景与数据集整体设计思路1.1 玻璃清洁检测到底解决了什么问题玻璃这种材质在视觉感知里属于“难缠”的目标。它不像行人、车辆那样有清晰的轮廓和稳定的纹理透明属性导致背景会直接透过来反光属性又会让周围环境映射在表面。你看着是一扇玻璃门模型看到的可能是门外的一棵树、走廊里的灯箱和玻璃上的脏污混在一起。这种情况下传统的图像处理方法比如边缘检测、颜色阈值分割几乎全部失效只能靠深度学习模型去学习“脏污区域”与“干净玻璃”之间的高维差异。从业务痛点来看玻璃清洁检测的需求集中在几个典型场景。商场和写字楼的公共区域玻璃需要巡检人员频繁查看是否留有手印、水渍酒店大堂的玻璃隔断和旋转门清洁质量直接影响客户第一印象还有机场、地铁等交通枢纽的玻璃幕墙面积大、清洁频次要求高。以前这些场景靠人工巡检效率低且标准不统一。有了目标检测模型之后可以配合巡检机器人或者固定摄像头自动输出玻璃清洁状态的判断结果再调度保洁人员精准处理这就是这个项目最核心的价值。1.2 场景覆盖与类别定义从“脏不脏”到“哪里脏”这期数据集在设计类别时没有把“脏污”当成一个笼统的概念而是按照实际清洁作业里的反馈拆成了两个维度。第一个维度是位置玻璃上的脏污可以出现在玻璃本体区域也可以集中在下沿、角落、把手附近第二个维度是形态水渍、灰尘、手印、泥点、划痕它们的视觉特征差异其实非常大。我最终把标注类别收敛成了三类water_stain水渍、dust_area积灰区域、smudge手印/油污。有人可能会问为什么不把划痕也单独做一类实际标注过程中你会发现划痕和细长水痕在低分辨率图像里几乎无法区分强行分成两类只会增加标注难度和模型的学习负担。所以划痕在当前的版本里并入了water_stain类别等后续采集到更多高分辨率特写样本之后再考虑单独拆出。每张图像的尺寸统一处理为1920x1080或者1280x720确保在保留细节的前提下控制标注工作量。符合检测条件的目标框数量每张图控制在1到8个之间避免出现一张图上几十个框导致训练时背景信息不足的问题。整套数据集一共包含超过2000张已标注图像并且按照8:1:1划分为训练集、验证集和测试集目录结构直接用images和labels分开存放方便各类YOLO版本直接读取。1.3 数据集的难点为什么玻璃检测不能套用通用目标检测思路通用目标检测数据集里的目标比如COCO里的80类物体大多具备“实体感”有明确的边界即使遮挡严重也至少能看出一个局部轮廓。玻璃目标完全没有这种便利。一块非常脏的玻璃脏污区域本身就是检测目标但它的边缘往往和背景融为一体不可能用矩形框完美框住。我在标注过程中体会最深的一点是玻璃上的脏污区域矩形框的四个边到底切在哪里直接影响模型的学习效果。切得太紧会把脏污边缘的半透明过渡地带排除在外模型学到的是一个“干净的脏污核心”切得太松框里混入了大量干净玻璃和背景内容背景特征和脏污特征混在一起模型就会混乱。因此我能给出的一个明确经验是——矩形框应当包含完整脏污区域同时允许边缘贴合透明度过渡区但不能超出到可见的背景物体区域。这样模型学到的特征边界比较干净推理时给出的预测框也更稳定。2. YOLO标注格式详解一层层拆开看2.1 一张图看懂YOLO标注格式YOLO系列使用的标注格式是每张图片对应一个同名txt文件文件里的每一行代表一个目标对象格式固定为五列数字class_id x_center y_center width height。这里的x_center y_center width height都是归一化坐标取值范围在0到1之间计算方式是目标框的实际像素值除以图像的宽或高。举个例子一张1920x1080的图像里某个脏污区域左上角坐标为(400, 300)右下角坐标为(800, 700)那么对应的标注应该这样算框宽 800 - 400 400归一化宽度 400 / 1920 ≈ 0.2083框高 700 - 300 400归一化高度 400 / 1080 ≈ 0.3704中心点x (400 800) / 2 600归一化 600 / 1920 0.3125中心点y (300 700) / 2 500归一化 500 / 1080 ≈ 0.4630对应txt文件里的内容是1 0.3125 0.4630 0.2083 0.3704其中第一个数字1表示目标类别是dust_area前提是你把类别索引定义为0是water_stain1是dust_area2是smudge。这类转换逻辑建议直接写一个小脚本批量处理不要手动计算光靠手算不仅慢还极其容易出错。2.2 玻璃目标的标注间距与争议处理原则标注工具方面我推荐用LabelImg或者AnyLabeling。LabelImg是老牌工具打开慢一点但功能稳定适合批量操作AnyLabeling交互更顺滑支持快捷键自定义而且对YOLO格式的支持是原生级别的导出之后不需要额外转换。真正需要仔细说明的是标注过程中的“争议处理”原则。三个标注员同时标一张图同一个脏污区域A标出来的框和B标出来的框可能相差20%这不是谁对谁错的问题而是大家对“脏污边界”的心理认知不一致。我的做法是制定三条硬性规则凡是肉眼在屏幕距离60cm左右能清晰识别的脏污区域必须标注哪怕形状不规整。单个脏污区域面积小于整张图像面积的0.5%时不标注。这个比例是通过实际训练测试得出的容忍阈值低于这个阈值的脏污检测难度太大标注成本高且容易给模型引入噪声。当脏污区域互相距离非常近近到矩形框重叠面积大于30%时合并成一个目标框。这三条规则看起来简单但严格执行之后标注一致性从原来的60%左右提升到90%以上对后续模型训练的稳定性帮助非常大。2.3 标注格式的自动化校验方法标注数据做完之后不能直接扔给训练脚本就完事。YOLO格式的txt文件非常容易出错常见的情况包括归一化坐标超出0到1的范围、框的宽度或高度为0、类别索引超出实际类别总数、txt文件与对应的jpg文件名不匹配。这些错误在训练时往往不会直接报错而是表现为模型loss异常、mAP忽高忽低。我建议训练之前跑一遍数据校验脚本检查每张图片是否都有对应的txt标注检查txt内容是否满足基本格式检查目标框面积是否过小。一个简单的判断逻辑是如果某个目标框的面积小于图像面积的0.01%基本可以确定是标注异常要么删掉这一条要么返回去重新检查原图。这个过程属于“数据工程”里最脏最累但最不能省的环节为了省这几分钟导致模型训歪得不偿失。3. 数据采集与清洗的完整实操路径3.1 图像采集怎么拍出让模型学得会的照片采集玻璃脏污图像最大的坑在于“你以为你拍到了脏污实际上相机把反光拍得比脏污还清楚”。我在第一期采集时就踩过这个坑大白天拿手机对着商场玻璃橱窗拍拍回来的照片里玻璃上的灰尘完全被天空和对面楼宇的反射光淹没了每张照片看着都像是“干净的脏玻璃”根本无法标注。后来总结出的经验是采集玻璃脏污状态图像必须在三个维度上控制变量。第一个是时间优先选择早晨或者傍晚的侧光时段这时候玻璃上的脏污会因为光线入射角度产生明显的漫反射差异肉眼看得清楚模型也学得明白第二个是拍摄角度尽量不要正对玻璃拍而是与被拍摄表面保持30度到60度的夹角这样既能拍到脏污本身的纹理又不会让镜面反射直接进入镜头第三个是光源条件室内场景可以带一个便携补光灯从侧面打光人为制造脏污和干净区域之间的亮度差。如果是在清洁机器人上部署采集数据时还要尽量贴近机器人的实际作业视角。很多人忽略这一点拿手机在人的高度拍了一堆数据结果机器人底盘摄像头的高度只有20cm视角完全不一样一到现场模型精度直接掉一截。最稳妥的做法是前期就把相机固定在机器人上模拟真实运行场景去拍。3.2 图像清洗去重、去模糊、去干扰采集回来的原始图像里大概有30%到40%是不能直接进入标注流程的。最常见的问题是相似度过高机器人在固定点位连续拍摄同一个脏污区域出现几十张几乎一样的图如果不做去重训练集里这个区域的特征会被反复强化模型就过拟合了。去重我用的是感知哈希算法pHash。具体做法是把每张图缩放到32x32的灰度图计算64位的哈希值然后比较不同图像之间哈希值的汉明距离。距离小于5的判定为近似重复图像只保留一张。这个方法速度非常快2000张图全量跑一遍也就几十秒。还有一个容易被忽略的环节是去除带有强烈反光的图像。不是所有反光都有害但那种反光区域覆盖面积超过图像1/3、并且反光正好叠在脏污目标上的图像必须剔除。原因很简单模型会把反光特征和脏污特征关联起来后续在实际场景中遇到没有反光的脏污反而识别不出来了。筛选这类图像最有效的方式还是人工浏览一遍虽然耗时间但这一步能省掉后面调试模型时的大量麻烦。3.3 标注类别边界水渍、灰尘、手印怎么区分标注规范这事说得再多都不如直接看例子管用。我给当时一起标注的同事做过一张内部用的对照表直接贴在工位上现在整理出来分享给需要的朋友水渍干燥后留在玻璃上的钙化痕迹呈白色或灰白色不规则圆斑边缘模糊通常带细小的颗粒感。积灰区域玻璃表面附着均匀或不均匀的尘土呈灰褐色面积偏大透明度降低用手指触摸有明显颗粒感。手印/油污指纹、手掌印或油渍边缘清晰反射率与干净玻璃差异明显在斜射光下尤为醒目。实际标注中最大的争议点是水渍和手印。水渍干了以后会产生白色残留手印里面的油脂成分在玻璃上也会形成白色痕迹。我的处理原则是如果痕迹中可见明显的指纹线条或者手掌轮廓判为手印如果没有具体形态、呈现为无规律的斑点状或条带状判为水渍。按这个原则处理虽然不能保证100%准确但至少能让不同的人标注结果保持可接受的一致性。3.4 数据增强哪些手段对玻璃检测真正有效关于数据增强策略我也做了一组对比实验。最终结论是颜色抖动、亮度调整、随机缩放这几种方法对玻璃脏污检测有明显帮助而随机旋转90度、水平翻转这些方法需要谨慎使用因为玻璃上的水渍和手印是有“重力方向”的。举个例子手印通常是手指从下往上或者从上往下抹出来的痕迹垂直方向上的纹理信息非常关键。如果做水平翻转相当于把手印的左右方向反转但脏污形态本身的特征方向还在模型还能学会如果做90度旋转垂直纹理变成了水平纹理和实际情况完全不符模型反而学歪了。所以我的做法是只做水平翻转不做垂直翻转和90度旋转亮度调整的范围控制在正负20%随机缩放控制在0.8到1.2之间。还有一个玻璃检测特有的增强方式是“随机叠加反光”。具体的做法是在训练图像上叠加半透明的白色渐变条或者高光圆形模拟不同角度的反光效果。这个操作能让模型见过更多样的玻璃表面情况提升在实际场景中的鲁棒性。4. 用这套数据集训练YOLO模型的完整实操记录4.1 数据集目录结构与配置文件准备为了让不同版本的YOLO都能直接读取建议严格按照下面的目录结构来组织文件glass_dirty_dataset/ ├── images/ │ ├── train/ │ │ ├── 0001.jpg │ │ └── ... │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ │ ├── 0001.txt │ │ └── ... │ ├── val/ │ └── test/ ├── data.yaml └── README.md训练之前需要准备一个data.yaml内容如下train: ./images/train val: ./images/val test: ./images/test nc: 3 names: [water_stain, dust_area, smudge]这里有一个容易踩的坑train和val的路径建议使用相对路径或者使用绝对路径但一定要确保路径指向的是images目录而不是包含images的上级目录。我在早期操作中经常写错导致训练时YOLO框架找不到图片报错信息还不直观排查半天才发现只是路径问题。4.2 基于YOLOv8的训练命令与参数调优我实际用来训练这个数据集的框架是ultralytics提供的YOLOv8这个版本在数据加载、训练流程和部署导出方面都很成熟适合作为第一个跑通全流程的版本。训练命令如下yolo train \ modelyolov8s.pt \ dataglass_dirty_dataset/data.yaml \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ project./runs/glass_train \ nameexp_001有几个参数值得单独说明。imgsz我选的是640而不是1280因为玻璃脏污目标本身的尺寸偏大640输入尺寸足够捕捉纹理特征同时训练速度可以控制在可接受的范围。如果你后续要检测的是细小的划痕那imgsz就需要提高到1280以上但这也会让显存占用成倍增长。patience20的意思是如果连续20个epoch在验证集上的指标没有提升训练就会提前停止。这个参数对节省时间很有用我在实际训练中大约跑到110个epoch就触发了早停效果比硬跑满150个epoch要更好因为后期模型已经开始过拟合了。另外一个值得尝试的是数据增强参数配置。YOLOv8默认开启的增强策略对玻璃检测不一定是最优的我在训练脚本里额外加了参数yolo train \ modelyolov8s.pt \ dataglass_dirty_dataset/data.yaml \ epochs150 \ imgsz640 \ batch16 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4 \ degrees0 \ fliplr0.5 \ scale0.5 \ translate0.1这里把degrees0固定下来禁止旋转增强fliplr0.5保留水平翻转scale0.5允许一定程度的缩放。这套配置训出来的模型在验证集上的mAP50比默认配置高出大约3个百分点效果提升在脏污边缘模糊的样本上尤其明显。4.3 训练过程与关键指标解读训练过程中需要重点观察两个指标一个是train/cls_loss分类损失另一个是val/box_loss边界框回归损失。如果分类损失下降正常但边界框损失一直徘徊不降说明标注框的边界定义有问题需要回到数据层面检查如果两个损失都在下降但验证集mAP上不去大概率是训练集和验证集的分布不一致比如训练集里大量是室内玻璃验证集里却混进了很多室外橱窗照片。我在跑完150个epoch之后最终在验证集上的表现大致是mAP50达到0.78mAP50-95达到0.52。这个精度水平在实际场景中已经具备初步使用价值但要直接上线部署还需要继续补充现场数据做针对性微调。不过作为一个免费开源的数据集这个表现足够支撑大家跑通流程、验证方案、做算法预研。4.4 轻量化部署从YOLOv8到端侧模型的经验训练好的模型最终要落地通常会涉及模型导出和轻量化。Ultralytics框架支持直接导出为ONNX、TensorRT、OpenVINO、NCNN等多种格式。如果你要部署到Jetson系列设备上推荐TensorRT如果部署到树莓派或者RK3588这类边缘设备推荐导出为NCNN格式。如果你观察最近的模型轻量化趋势会看到很多超轻量化模型可以把体积做到5MB左右同时在边缘设备上跑到实时帧率。玻璃清洁检测这类任务对实时性要求不算苛刻每秒处理2到3帧就足够满足巡检需求所以其实不需要一味追求极小模型关键是找到精度和速度的平衡点。我在实际项目里使用的是YOLOv8s导出TensorRT后的FP16版本在Jetson Orin Nano上推理延迟大约18毫秒完全够用。5. 常见问题与排查技巧实录5.1 高频问题速查表根据我在标注和训练过程中积累的经验整理了一张问题排查表按出现频率排序问题现象可能原因排查思路与解决方案把玻璃反光里的行人误检为手印训练样本缺乏反光干扰增强数据里加入随机反光叠加在采集时特意保留部分带反光的图像透明玻璃背后的物体被误检为脏污标注框过松背景信息混入检查标注框是否紧贴脏污边缘放宽到包含过渡区域的策略需谨慎积灰区域漏检率居高不下积灰目标在图像中占比太小提高输入分辨率到1280在粗检测基础上增加一个细粒度分类分支模型在夜间灯光场景表现差训练集缺少暗光样本补采低照度图像在增强环节加入亮度下调策略连续视频帧中预测框不稳定目标框标注边界不一致统一标注规范对预测结果增加时序平滑后处理5.2 训练Loss异常波动的三个排查方向如果你第一次训练就发现loss曲线上下剧烈跳动首先不用慌这是目标检测训练里比较常见的情况。有一个需要优先检查的方向是学习率是否过高尤其是用了较大的batch size时默认lr00.01可能会让loss在前期震荡明显。我的经验是batch size超过32时把lr0降到0.005训练稳定性会有明显提升。第二个需要检查的方向是标注文件中是否存在极端的目标框。比如某个目标框宽度或者高度只有1到2个像素在模型下采样过程中很容易被直接忽略但它的梯度信号会干扰正常目标的学习。建议处理方式是直接过滤掉面积占比过低的标注框。第三个方向是检查是否出现了类别不均衡。如果water_stain有800个目标而smudge只有50个目标模型大概率会把数量少的类别学成背景。我给的解决方法是做类别重加权具体来说在data.yaml里增加每个类别的基础权重或者干脆为少数类别复制样本数据让它们的出现频率不要差距太大。数据不平衡的问题在玻璃脏污检测里尤其突出因为手印往往比水渍和积灰更少出现。5.3 从标注规范到模型精度最容易忽视的细节很多人在训练完模型之后发现检测效果不理想第一反应是换更大的模型、加更多数据很少有人会回头检查标注规范本身。这里我想分享一个真实案例有一轮训练结束后模型在验证集上把很多玻璃边框当成了脏污目标。排查了半天才发现标注人员在标注时没有区分玻璃边框和玻璃表面的脏污把门框上的黑色胶条也标成了smudge。这种错误不会导致训练报错但会让模型学到完全错误的目标概念。这就是为什么我在整个项目里反复强调标注规范的重要性。如果你的项目有专职标注团队务必要在标注之前进行至少半天的培训并且每天随机抽检10%的标注结果如果你是个人开发者自己标注也建议在标注完第一批数据后隔一天再回头看一遍——脱离标注状态后再审视能发现很多当时没注意到的问题。这个习惯让我避免了好几次“模型训完发现是数据问题”的无用功。5.4 数据集的扩展与后续版本规划目前这版数据集在室内玻璃场景下的表现相对可靠但要覆盖到更多业务场景还需要持续扩展。我个人的规划是后续补充三个方向第一个是夜间和暗光环境下的玻璃脏污样本这类样本在商场打烊后的巡检场景中尤其重要第二个是不同材质玻璃比如磨砂玻璃、压花玻璃、镀膜玻璃它们表面的脏污视觉特征差异非常大需要单独采样第三个是不同类型的光源反射干扰样本让人工光源在玻璃上的反射特征进入训练集减少模型在现场环境下的误检。如果你拿到了这期数据集也欢迎在项目基础上补充自己的数据再训练逐渐形成适合自己业务场景的私有数据集。写在最后的一个小建议真正动手做这个数据集之后我才意识到玻璃清洁状态检测难的不在模型结构而在于“什么是脏”这个定义本身。人与人对脏污程度的主观判断差异极大计算机更是如此。因此无论你是用YOLOv8还是未来更新的模型核心精力都应该放在数据质量上——标注规范统一了数据分布合理了模型的精度提升就是水到渠成的事。这套免费分享的数据集希望能帮你跳过最痛苦的采集和标注阶段把时间花在真正有价值的算法落地和业务验证上。
返回列表