YOLOv11实战:变电柜指示灯检测与状态判读全流程 变电柜的指示灯检测听起来是个比车牌识别还简单的活儿无非是训练一个目标检测模型把柜面上亮着的小灯圈出来。可真把这一套系统从数据集做到部署我却发现这类任务的坑远比想象中多指示灯在画面里往往只有十几个像素大小亮灯和灭灯的状态差异会在不同光照条件下剧烈变化柜体金属边框的反光还会在画面里制造出一堆假目标。这篇文章就记录我用 YOLOv11 从零搭建变电柜开关指示灯检测系统的完整经验重点讲数据集标注、小目标训练调优、状态判读策略以及部署时踩过的坑适合电力巡检自动化和工业仪表识别方向的同学参考。1. 变电柜指示灯检测的真实难点为什么通用目标检测模型容易翻车1.1 目标尺寸小到超出常规认知先算一笔账。变电柜柜面宽度普遍在 0.8 米左右高度 1.6 米上下而指示灯和开关拨杆的物理尺寸通常在 10 到 15 毫米。用 2000×1500 分辨率的画面拍摄一个指示灯在图像里大约只有 10×10 像素如果现场用的是常规 1080p 摄像头目标更是缩小到 5×5 像素的水平。这是什么概念COCO 数据集里的“小目标”定义是小于 32×32 像素而变电柜指示灯比 COCO 的小目标还要小一到两个量级。通用目标检测模型在 COCO 这类数据上训练时天然对大尺寸、语义清晰的目标更敏感默认的 640×640 输入分辨率会把原本就很小指示灯进一步压缩。我一开始直接拿 YOLOv11s 默认配置跑了一版结果漏检率惨不忍睹尤其是灭灯状态几乎有一半灯没被框出来。这个教训说明在这个场景里输入分辨率不是可以随意取舍的参数而是决定系统能不能用的前提条件。1.2 状态识别与目标检测之间存在天然错位业务方要的从来不是“这里有一个灯”而是“这个灯当前是亮还是灭”“这个开关当前是开还是关”。但 YOLOv11 这类目标检测模型输出的是“边界框 类别”它擅长回答“这个区域有个什么东西”不擅长直接回答“这个东西当前处于什么状态”。我在项目里一开始把类别设计成“开关开”“开关关”“灯亮”“灯灭”四个类跑起来后发现一个很微妙的问题同一个指示灯亮的时候呈现高亮红色或绿色灭的时候呈现灯罩的灰白色两者在某些光照条件下边界并不清晰。模型在“亮”和“灭”之间反复摇摆框的位置也跟着轻微跳动。这里的关键在于状态判读不能只依赖单帧检测结果需要一套额外的逻辑来稳定输出。这个后面专门展开说。1.3 光照、反光、遮挡才是真正的敌人相比通用场景变电柜的视觉环境极不友好。柜面金属边框在侧光下会产生形状类似指示灯的高亮反光带柜门玻璃会倒映室内灯管指示灯防尘罩用久了还会积灰导致同一个灯在不同时期拍出来的亮度和色相完全不同。训练集如果都是“干干净净”的正视角照片部署后第一个阴雨天就会出现大量误报。我后来专门花时间收集了多个时段、多种光照、不同柜面的图像甚至人为在镜头上制造了一些轻微的污渍效果做数据增强才把现场的误报压下来。这个体会排在所有技术细节前面在这个场景里数据的多样性比网络结构重要得多。1.4 场景定位这是一套“检测 判读”复合系统做这个项目之前我一直把“检测系统”理解成“训练一个模型输入图片输出框和类别”。做完变电柜项目后我明确意识到这样理解太窄了。实际系统应该是三层第一层用 YOLOv11 输出候选目标和初始类别第二层按目标的物理位置做跨帧关联积累状态置信度第三层用业务规则把“开关开 对应指示灯亮”这类组合转换为可读的巡检结论。后面三层中的任何一层做得糙最终效果都会很差而且很难定位是模型的锅还是业务的锅。2. 数据集构建小目标标注与状态类别平衡的实操细节2.1 采集固定机位录视频再抽帧远比四处拍照高效数据集是整个系统的地基但采集方式直接决定后续标注质量。我第一版数据是拿着手机在变电柜前不同角度拍照片结果标注的时候头都大了同一个灯在画面里的位置和角度各不相同标注员需要反复确认“这个灯到底对应物理上的哪一个”效率极低还容易标串。后来改成固定机位录制视频再抽帧效果好很多。把摄像头或手机稳定在三脚架上正对柜面录制不同时段、不同柜面状态下的视频然后按固定间隔抽帧。这样做有三个好处一是图像内容稳定标注时能快速建立“这个位置的灯就是物理上的某个灯”的映射二是能自然覆盖同一目标在不同状态下的连续变化三是方便后续做时序关联因为知道哪些帧是连续拍的。抽帧时不要只抽状态剧变的片段否则数据分布会偏向状态切换的瞬间反而不利于学习稳定状态下的特征。2.2 类别设计先想清楚输出需求再定类变电柜开关指示灯检测的类别定义直接影响后续所有环节。我在项目里对比过两种方案方案标注类别优点缺点方案A开关开、开关关、红灯亮、红灯灭、绿灯亮、绿灯灭一个模型直接输出业务要的结果逻辑简单类别边界可能模糊亮灭状态在光照影响下容易错分方案B开关、指示灯物理类别 单独的状态分类分支状态判定灵活可解释性强工程上需要两阶段流程复杂训练成本更高我实际采用了方案A但把类别细化成六类把灯的“颜色 状态”直接揉进类别里。这样做的直接好处是模型输出的每个框都直接对应业务关心的结论做告警逻辑时不需要额外推断。缺点也很明显类别数量变多后相似类别比如红灯亮和绿灯亮形状可能很像之间的区分难度增加。所以在标注时对状态类别不明显的样本我宁可多标一些“不确定”倾向的辅助数据也不强行标成某一类后面在判读层再做兜底。2.3 标注细节小目标的框怎么画直接影响训练稳定性目标小意味着标注误差的影响被放大。大目标画框偏两三个像素无关痛痒指示灯如果偏了十几个像素框涵盖的内容就完全变了。标注时最忌讳只标最亮的发光内芯因为亮灯和灭灯状态下发光区域的范围完全不同模型会被搞糊涂。我的经验是把指示灯发光区域外扩到灯罩边缘给模型一个相对稳定的边界参考。开关则要把拨杆手柄本身完整包含进去而不是连后面整个底座一起框否则模型学到的特征里混入了大量无关背景。此外由于小目标在整幅画面中占比很小模型能利用的上下文信息有限标注时框的“紧致度”特别重要。太紧模型学不到周围背景信息太松多个指示灯连在一起时框容易粘连。我在实践中推荐“紧贴灯罩边缘再外扩 2 到 3 个像素”这是一个平衡点。2.4 数据量、类别平衡与增强策略的取舍每个类别至少需要 150 到 300 张有效样本这是起步线。变电柜场景中红灯灭、绿灯灭这类状态往往很少出现属于天然的长尾类别。我在项目里针对少数类别做了两种补数据的方式一是从不同角度补拍二是对已有样本做轻微的仿射变换和亮度抖动让同一张图产生多个变体同时保持状态语义不变。数据增强是双刃剑。mosaic 增强在通用目标检测中几乎是标配但在指示灯这种极小目标场景里mosaic 会把很多目标切掉或缩到几像素大小模型大量看到这种残缺样本后反而会漏检。我在 ultralytics 里把 mosaic 概率从默认的 1.0 调低到 0.5同时配合较小的平移和缩放效果反而更好。HSV 增强更需要谨慎指示灯状态判断高度依赖颜色和亮度hsv_h 我设置到 0.01hsv_s 和 hsv_v 控制在 0.2 以内避免把“红亮灯”增强成“橙亮灯”造成标签噪声。2.5 验证集划分不能随机要按场景划分这一点很多教程不会提。同一个视频连续抽帧出来的几百张图片相似度极高如果随机划分训练集和验证集验证集会包含大量和训练集高度相关的样本mAP 虚高得离谱一部署就露馅。正确做法是按柜面或时间段来划分同一台柜面的所有帧必须全部落在同一个集合里不允许一部分进训练、一部分进验证。这样才能真实反映模型面对没见过的柜型和光照条件时的泛化能力。3. YOLOv11 训练配置模型选型、输入分辨率与小目标调优3.1 为什么选 YOLOv11 而不是其他模型选择 YOLOv11 有几个实际考量。相比前代 YOLOv8YOLOv11 在 backbone 中引入了更高效的 C3k2 模块和基于空间注意力的 C2PSA 结构在保持推理速度的同时提升了特征表达能力检测头沿用了解耦设计分类和回归分支分离训练收敛更稳定再加上 ultralytics 生态对训练、验证、导出、部署整个流程支持完善工程上手成本低。这套项目不是学术实验需要短时间内落地生态成熟度比理论性能上限更重要。但必须承认YOLOv11 的默认配置并不是为指示灯这种极小目标设计的。默认 640 输入分辨率、默认增强策略、默认的检测头尺度都对小目标不够友好。所以选型只是第一步真正的功夫在后面的参数配置和针对性补充。3.2 不要只跑默认参数关键超参数设置记录我项目里最终的训练配置如下供参考参数值说明image size1280从 640 提到 1280 后小目标漏检率下降最明显batch size16取决于显存能大尽量大小 batch 下 BN 统计不稳定epochs300配合早停小目标任务收敛明显慢于大目标optimizerAdamW对小目标场景收敛更平稳SGD 也可以但需更精细调 lrlr00.001比默认的 0.01 低一些训练更稳定mosaic0.5降低 mosaic 概率减少小目标被切没的样本hsv_h0.01色相扰动调小避免状态颜色失真hsv_s0.2饱和度扰动适度hsv_v0.2明度扰动适度太大会破坏亮灭差异scale0.5缩放范围适中1280 输入分辨率是性价比最高的改动。同样的模型参数从 640 换到 1280漏检率能下降接近一半虽然训练时间和显存占用都明显上涨但在检测系统里这些代价是可以接受的。如果现场是工控机部署推理速度受限可以训练时用 1280导出时再用 TensorRT 做 INT8 量化来提速效果比直接用小分辨率训练好很多。3.3 小目标专项改进P2 检测层、注意力机制与 CARAFE跑完基线后我只做了模型结构层面的针对性改动不追求堆叠模块。第一个是 P2 检测层。YOLOv11 默认的检测头下采样倍数分别是 8、16、32对应三个尺度。对 10 像素左右的指示灯来说stride 8 的特征图仍然太粗很多细节已经丢失。增加 P2 层即 stride 4 的检测头相当于让模型在更高分辨率的特征图上寻找小目标对召回率有明显帮助。代价是计算量增加显存占用也变大是否值得要看你现场的目标尺寸分布。第二个是注意力机制。我对 backbone 输出的特征图加了一个轻量化的 EMA 注意力模块它能在不显著增加计算量的情况下让模型更关注小目标所在的区域。自注意力机制在理论上也能起到类似作用但对这种画面结构相对固定的工业场景来说收益未必比 EMA 这类轻量方案高。如果你的数据集不大动 backbone 结构要特别谨慎引入过多参数反而会导致过拟合。第三个是 CARAFE 上采样算子。它比默认的双线性上采样能保留更多细节信息对密集小目标场景有一定帮助。但同样它带来的提升有限不建议为了“听起来高级”强行引入。我总结的改进策略是先跑一版基线统计漏检目标都集中在哪个尺度、什么背景下再决定要不要加 P2 层或注意力机制。盲目堆模块的最大风险不是性能不升而是你根本不知道是哪个改动起的作用。4. 从检测结果到“运行状态”判读层的设计与误判压制4.1 模型输出不能直接当告警这是整个系统里最容易翻车、也最容易被忽略的一层。YOLOv11 输出的是每一帧的检测结果但指示灯的亮灭状态在单帧层面是不稳定的。同一个物理灯这一帧被识别成“红灯亮”下一帧因为轻微抖动、光晕变化、模型置信度波动可能就变成“红灯灭”。如果直接拿单帧结果去触发告警一个正常运行的变电柜一天能报出几百条虚假告警。我的做法是引入时间维度的稳定性判断。核心思路很简单用检测框的中心点和尺寸做跨帧关联确定“这一帧的框对应上一帧的哪个物理灯”然后对同一个物理灯的状态类别做指数滑动平均。状态跳变要连续满足 5 帧以上才确认否则维持原状态。这样一来单帧噪点被自然平滑掉告警可信度大幅提升。4.2 双阈值策略宁可输出“待定”也不乱判类别置信度阈值的选择对状态判读影响很大。常规做法是设定一个阈值高于它就认为属于当前类别。但在指示灯场景里亮灯和灭灯在光照不利时区分度很低一个固定阈值很容易让模型在两个状态之间反复横跳。我采用了双阈值策略设一个高阈值和一个低阈值。置信度大于高阈值时输出“红灯亮”低于低阈值时输出“红灯灭”介于两者之间时输出“状态待确认”等待后续帧的判决。这样虽然会短暂延迟判定结果但能显著减少误报。对电力巡检场景来说一个稳定的“待确认”状态远比一个频繁乱跳的“故障告警”更容易让业务人员接受。4.3 规则层把“一个灯的状态”变成“一条巡检结论”检测和判读完成后最后一步是业务规则层。变电柜场景里开关状态和指示灯状态之间通常存在逻辑关联比如某个开关处于“关”状态时对应的控制灯应该熄灭如果这时候灯还是亮的说明存在异常。这类判断用简单的决策表就能实现把每个目标的物理位置 ID 和业务含义绑定再把状态组合映射为“正常”“异常”“需人工复核”三类结论。我在项目里把这一步做成了一个独立的规则配置模块跟模型完全解耦。业务方后续想调整告警逻辑不需要重新训练模型改配置就行。这套架构带来的维护成本节省比选型时省的那一点推理时间更有价值。5. 现场实测漏检、误报与背后的一连串排查5.1 badcase 分类先搞清楚是漏检还是误报系统部署到现场后我遇到了一批典型问题按根因分类如下现象根因应对方案高亮白灯周围出现光晕检测框忽大忽小曝光过度导致灯体边缘丢失调低相机曝光或对图像高光区做压缩处理金属边框反光被识别成指示灯训练集缺少反光负样本补充不同光照角度的负样本数据灭灯与深色柜面背景融为一体目标对比度过低对柜面 ROI 区域做 CLAHE 对比度增强多个相邻指示灯被框成一个框NMS 阈值设置不当或目标间距过小调整 NMS 参数或提高输入分辨率拉开像素间隔红灯亮和绿灯亮互相错分两类目标形状几乎一致只靠颜色区分检查训练集颜色平衡必要时引入颜色校正预处理把 badcase 按“漏检”和“误报”两个维度分开统计特别重要。漏检大量集中在极小目标上说明方向是输入分辨率和检测层尺度误报集中在特定背景区域说明是数据覆盖问题。两者混在一起处理最容易做无用功。5.2 图像预处理的补救作用不改模型结构的情况下图像预处理也能救回来一部分问题。我试过在推理前用 CLAHE 对柜面区域做局部对比度增强灭灯与背景的边界明显清晰了漏检率下降了几个点。但这里有一个坑如果对全图做增强金属边框的反光也会被同步放大误报反而更多。所以增强只能作用于柜面 ROI不能全局套用。这个 ROI 可以预先标定好因为摄像头机位固定后柜面区域基本不变。5.3 部署后持续收集 badcase 比调参更有用部署上线不等于结束。服务器端要定期保存那些置信度徘徊在阈值附近、或者人工复核时发现判断错误的图片按周期回灌训练集。第一次迭代可能只解决了一类误报但持续积累两三轮之后模型对现场光照环境的适应能力会有质变。这套“数据飞轮”的做法比反复调模型参数带来的收益大得多。6. 部署落地与后续扩展6.1 推理性能与硬件选型如果只是实验演示用带 GPU 的台式机就够了。但变电柜现场往往是工控机甚至可能是 Jetson Orin 这类边缘设备。我的经验是先用 ONNX 导出模型在目标硬件上测一轮原生 FP32 的推理速度再决定要不要做 TensorRT 或 INT8 量化和精度校准。模型训练用 1280 分辨率部署时也尽量保持同样的输入尺寸不要为了省时间把推理分辨率降到 640否则训练时的改进会前功尽弃。如果现场确实跑不动 1280优先考虑用 TensorRT 的 INT8 量化而不是直接改小输入尺寸这样精度损失更可控。6.2 摄像头机位与拍摄角度建议摄像头机位往往是影响实际效果的隐藏变量。安装时要尽量正对柜面避免倾斜角度造成的透视畸变否则同一个灯在不同位置的大小差异会很大。柜门是玻璃材质时摄像头略微偏向一侧安装可以明显减少室内灯管的镜面反光。现场安装后务必从取景画面里人工确认一遍所有指示灯都在可视范围内不要出现角落里的灯被柜门边框遮住的情况。6.3 再往后走从“指示灯检测”到“自动巡检报告”检测系统稳定之后可以把目标 ID 与柜内设备编号绑定按时间戳将状态变化记录下来自动生成巡检报告。比如“9 时 15 分 32 秒2 号柜红灯亮持续 30 秒后复位”这类记录对运维人员有直接参考价值。如果再接入设备台账数据还能实现“柜号 灯位 状态 时间”的四维联动查询把单点检测能力扩展成一套完整的巡检工具。整个项目做下来我最大的感受是这套系统真正的难点从来不在 YOLOv11 本身而在于你能不能把数据采集、类别设计、状态判读和现场部署这些环节串起来。如果一开始就把所有精力放在模型结构上大概率会像我第一版那样得到一个在验证集上很好看、在现场却不停翻车的模型。先想清楚业务到底要什么再动手标注和训练才是这类工业视觉项目最稳妥的路径。