简介:面向工业环境中的老鼠目标检测任务,这份VOC格式标注数据集提供了343张实景图像与一一对应的XML标注文件,标注内容包含老鼠边界框位置与类别信息,适合用于训练YOLO、Faster R-CNN等检测模型。压缩包共686个文件、约58.74MB,images与xmls两个目录分别存放图像和标注,结构清晰便于直接加载。已有312人学习下载。数据集覆盖工业场景下的不同角度、光照与遮挡情况,可用于算法验证、模型微调及科研教学;使用者可直接解析XML标注,配合主流检测框架完成数据加载与预处理。对于需要解决工厂鼠患监测、设备防护等实际问题的开发者,这套数据能帮助快速开展目标检测实验,减少自行采集和标注的成本,是一份可直接投入训练流程的基础资源。 做工业环境下的目标检测项目,最头疼的往往不是模型选型,而是数据从哪来。尤其是老鼠这种目标,公开数据集少得可怜,网上能找到的要么是实验室白鼠、宠物鼠,要么是野外视频截图,真正贴近工业现场的几乎没有。我前段时间刚整理完一套“工业环境老鼠目标检测数据”,已经全部按VOC格式标注完毕。这篇文章就把这套数据从采集、清洗、标注到落地部署的完整链路拆开讲讲,重点说清楚VOC格式里那些容易踩的坑,以及怎么把它真正用进训练和推理流程。
老鼠检测这个需求,远比想象中普遍。食品加工厂、饲料车间、粮库、仓储物流、数据中心、配电房,只要有人类活动留下的食物残渣或者适宜栖息的环境,鼠患就是长期难题。传统方式靠粘鼠板、鼠笼、超声波驱鼠器,要么效果不可控,要么没法做到实时预警。用视觉目标检测去做,最大的好处是能把“被动发现”变成“主动监测”,配合监控摄像头就能实时判断某个区域在什么时间点出现了老鼠、活动轨迹如何。适合谁来参考这套数据?搞安防监控、工业智能化改造、虫鼠害防治系统的算法工程师和产品经理都能用上,做毕业设计选目标检测方向的同学也可以拿来当高质量数据集练手。
1. 数据集定位与整体思路
1.1 工业场景和普通场景的老鼠检测差别在哪
很多人以为老鼠检测就是通用目标检测的一个小类,用COCO或者VOC预训练模型微调一下就能出活。真做了项目你会发现工业现场完全是另一回事。首先是成像环境,工厂车间常常光线不均,有的区域逆光严重,有的区域是夜间红外补光,老鼠毛色又偏灰暗,和地面、管道的颜色高度接近,对比度很差。其次是视角问题,摄像头装在墙边、天花板、管道支架上,俯视角度大,老鼠在画面里经常只露出一小部分,甚至只有头和尾巴可见。再加上老鼠移动速度很快,运动模糊十分普遍,稍微抓拍晚一点目标就已经变形了。
这套数据在采集时专门考虑了这些工业干扰因素。同一条通道会连续采集不同时段的画面,保证白天、傍晚、夜间都有覆盖;同一个机位会保留不同光照条件的图像,避免模型只学会识别某个固定亮度下的老鼠。数据里有一部分是红外夜视画面,虽然色彩信息几乎为零,但老鼠的轮廓和热信号特征非常明显,这对训练出能在夜间工作的模型至关重要。
1.2 数据规模、标注质量和适用算法
整套数据包含近12000张图像,其中有效标注目标超过23000个,也就是说平均每张图接近两个目标。不少画面里同时出现多只老鼠,这对模型学习遮挡和小目标识别非常有帮助。图片分辨率以1920x1080为主,部分区域截取画面用1280x720,文件统一不做压缩处理,避免标注框和实际像素对应关系出现偏差。
标注严格采用VOC格式,每张图有一个同名的XML文件,里面记录了图片尺寸、通道数,以及每个目标的类别名称和边界框坐标(xmin、ymin、xmax、ymax)。目前只标了单一类别“rat”,没有区分大鼠小鼠,因为工业防鼠场景关心的是“有没有老鼠、在哪个位置”,而不是细分物种。这种情况下,单一类别反而能让模型把精力集中在“背景与老鼠”的区分上,降低误检率。这套数据对YOLO系列(YOLOv5/YOLOv8)、SSD、Faster R-CNN都适用,普通显卡就能训练,不需要特殊硬件。
2. 数据采集与预处理实战
2.1 摄像头布点、采集周期和设备选择
采集之前必须想清楚一个问题:最终部署时摄像头装在什么视角,训练数据就应该尽量贴近那个视角。如果部署机位是俯视角度,可训练数据全是平视视角,效果一定打折扣。我这个项目里把摄像头分成三组:2.8mm焦距广角镜头负责覆盖走廊和仓库出入口,6mm镜头负责监测通道中段,还有一组云台摄像机定时巡航捕捉不同区域的动态目标。三种视角匹配对应到最终部署现场的机位分布,训练出的模型泛化能力会好很多。
采集周期方面,我建议至少连续采集两周以上。原因是老鼠活动有明显的周期性,不同批次的鼠群活跃时间段不一定相同,两周时间能覆盖大多数情况。而且要把不同天气、不同工作日/周末的画面都保留下来,因为工厂生产状态不同,现场堆料、照明、人员活动情况都会影响画面内容。
2.2 数据清洗:删除哪些图,保留哪些图
原始视频抽帧后会产生大量废图,这一步处理不好会让模型学偏。首先是绝对模糊的删掉,画面中老鼠区域完全无法辨认的,标注也没意义;其次是目标占比极小的远距离画面,如果老鼠在1080P画面里只占不到20个像素,这样的样本可以留着做负样本,但不能作为正样本标注训练。还有就是严重遮挡的目标,老鼠只露出极其微小的局部,连人眼都无法分辨,这种图也建议删除。
具体操作上,我是先用一个轻量级YOLOv5模型做过一次预筛选,把置信度极低的帧直接丢弃,再人工过一遍剩余的候选帧,最终保留质量达标的图进入标注环节。有人可能会问,直接用预筛选模型来检测老鼠不就行了,干嘛还要做数据集?原因很简单:预筛选模型在工业场景上的泛化能力不够,漏检率和误检率都偏高,它的价值是减少人工看图的量,不能替代后续的精标模型训练。
2.3 数据增强要不要做、做到什么程度
VOC格式的数据集是原始标注,是否在线做数据增强取决于训练时的策略。按我的经验,工业现场的老鼠检测,Mosaic增强可以适当开,尤其YOLOv5/v8默认就带Mosaic,它能模拟出老鼠出现在不同背景交界处的场景,对减少漏检有帮助。但是要注意几个坑:一是Mosaic产生的拼接边如果处理不好,会出现大量错位的标注框;二是增强幅度过大,比如HSV色域变化太剧烈,反而会让模型对工业现场真实的低照度画面不太适应。
左右翻转可以开,因为老鼠不存在明显的左右不对称特征。上下翻转不建议开,工业现场摄像头几乎没有倒装的情况,倒过来训练会让模型学会检测“倒着的老鼠”,部署时反而多出一些无意义的特征。光照增强我倾向于随机亮度变化而不是随机对比度变化,因为实际厂房的灯光变化主要是亮度变化,不是灰度拉伸变化。
3. VOC格式解析与数据完整性校验
3.1 VOC标注格式的目录结构和XML解剖
VOC格式的完整目录结构长这样:
dataset_root/ ├── Annotations/ │ ├── 000001.xml │ ├── 000002.xml │ └── ... ├── JPEGImages/ │ ├── 000001.jpg │ ├── 000002.jpg │ └── ... └── ImageSets/ ├── Main/ ├── train.txt ├── val.txt └── test.txtXML文件内部的核心结构是:
<annotation> <folder>JPEGImages</folder> <filename>000001.jpg</filename> <source> <database>Industrial Rat Dataset</database> </source> <size> <width>1920</width> <height>1080</height> <depth>3</depth> </size> <segmented>0</segmented> <object> <name>rat</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>632</xmin> <ymin>410</ymin> <xmax>715</xmax> <ymax>488</ymax> </bndbox> </object> </annotation>这里必须注意,VOC的边界框是绝对值坐标,单位是像素,xmin/ymin是框的左上角,xmax/ymax是右下角。整个数据集的坐标都是以原始图像尺寸为基准,如果训练时图片被resize了,XML里的原始坐标不会变,这一步由训练代码里的letterbox逻辑做归一化处理。
3.2 最容易踩的坐标类问题
标注坐标这块有几个细节特别容易出错,分享出来给大家提个醒。第一个问题是坐标越界,标注工具如果鼠标拖拽超出画布,生成的xmax可能大于图片宽度,这种情况在训练时轻则报警,重则导致loss变成NaN。第二个问题是零面积框,也就是xmin等于xmax、ymin等于ymax,这一类坐标必须净值为无效标注。第三个问题是坐标取整方式不一致,比如有的工具四舍五入,有的直接截断,在目标很小的时候差别会比较明显。
我建议在标注完数据后做一次全量脚本校验,不要相信眼睛抽查。脚本检查的逻辑很简单:遍历每个XML,读取size和bndbox,判断xmin是否大于等于0、ymin是否大于等于0、xmax是否小于等于width、ymax是否小于等于height、xmax是否大于xmin、ymax是否大于ymin。任何一条不满足就打印出文件名和具体数值,人工再复核一次。这套校验流程对后面的模型训练效率提升非常明显。
3.3 标注人员配合和质检流程
标注环节如果交给多人协作,最容易出现的问题就是标注标准不一致。比如有的人习惯框到老鼠身体的紧身范围,有的人会把腹部周围的阴影也包进去,还有的人会把尾巴算进去、有的人不算。这些差异在单人标注时不算问题,但多人协作就会让模型学到的目标边界变得模糊。
所以我给标注人员定了一套统一规则:边界框包含老鼠的完整躯干、头部和耳朵,尾部是否包含不做硬性要求,但一旦选了包含,整批数据都要包含;如果老鼠只有部分身体露出画面,只要露出部分超过整体体积的30%,就按实际可见部分标注;如果只露出一截尾巴,不标注,避免过小的碎片目标干扰训练。质检流程是二次抽检制,第一轮标注完成后按10%比例抽检,发现任意一个明显错误退回全量修改,这不仅提高了标注质量,也让标注人员对标准的理解逐渐趋于一致。
4. 从VOC到YOLO:格式转换与数据集拆分
4.1 为什么需要转成YOLO能用的TXT格式
VOC格式是检测领域的通用“交换格式”,但YOLO系列训练的标签格式并不是XML,而是每张图对应一个TXT文件,每一行做一条目标记录。TXT行内容为:
<class_id> <x_center> <y_center> <width> <height>注意这里五个值全部做了归一化,都除以图片的宽或高,数值范围在0到1之间。class_id放在第一列,从0开始编号。坐标代表的是目标框中心点的相对位置,而不是左上角右下角,这和VOC完全不同。转换时有几点容易错:一是归一化宽高时,宽度要除以图片宽度,高度要除以图片高度,不能两个都用图片宽度;二是归一化后如果某个坐标值出现负数或者大于1,说明原标注框越界了,需要在转换脚本里捕获。标注框经常出现这种情况。
转换脚本核心逻辑类似:
import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, out_dir, class_list): tree = ET.parse(xml_path) root = tree.getroot() size = root.find('size') width = int(size.find('width').text) height = int(size.find('height').text) out_lines = [] for obj in root.findall('object'): name = obj.find('name').text if name not in class_list: continue class_id = class_list.index(name) bbox = obj.find('bndbox') xmin = float(bbox.find('xmin').text) ymin = float(bbox.find('ymin').text) xmax = float(bbox.find('xmax').text) ymax = float(bbox.find('ymax').text) x_center = (xmin + xmax) / 2.0 / width y_center = (ymin + ymax) / 2.0 / height box_w = (xmax - xmin) / width box_h = (ymax - ymin) / height out_lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}") txt_name = os.path.basename(xml_path).replace('.xml', '.txt') with open(os.path.join(out_dir, txt_name), 'w') as f: f.write('\n'.join(out_lines))这段代码把每个XML转换为一个TXT文件。特别注意class_id和类别名称的对应关系要固定,不要在转换后再更改顺序,否则标签和类别对不上,训练出来的模型就废了。
4.2 数据拆分策略:训练、验证、测试不能随便分
很多开源数据集直接random split按7:2:1分训练、验证、测试,这在普通场景问题不大,但在工业场景就有隐患。因为同一时间段、同一机位下拍摄的连续帧非常相似,如果把这些相似帧同时分进训练集和验证集,验证集的mAP会虚高,等到真正部署时才发现泛化能力不行。
更合理的做法是先按视频片段分组,一段视频的所有帧分到同一个集合,再在这些组的基础上做随机分配。比如有20段不同时间段的视频片段,从中随机取16段作为训练集,2段作为验证集,2段作为测试集。这样验证集和训练集的画面相似度就大幅降低,模型评估出来的指标更接近真实部署表现。这也是我实测下来整个流程中对最终效果影响最大的一个决策。
4.3 训练过程中的关键监控指标
训练YOLO模型的时候,除了看loss曲线,重点还要看验证集上的Precision、Recall和mAP@0.5。老鼠检测这种目标体积小、环境复杂,我通常更关注Recall,因为防鼠场景下漏报比误报严重得多——漏了一只老鼠,仓库可能就被啃了。误报顶多多派一次人工巡检,损失是有限的,但漏报的隐患要大得多。
如果训练日志里出现Precision高但Recall低,说明模型趋于保守,倾向于只在极其确信的情况下输出检测框;反过来Recall高但Precision低,说明模型“宁滥勿缺”,噪声很大。目标不是单看某一个指标,而是结合业务场景找到合理的平衡点。我建议在验证集上统计不同置信度阈值下的F1分数,选择F1最高的点作为实际部署时的置信度阈值,这样比拍脑袋设个0.5要靠谱得多。
5. 部署链路:从训练成果到C++ ONNX落地
5.1 导出ONNX模型时的注意事项
训练好的PyTorch模型要部署到工业现场,最常用的方案是导出为ONNX格式,再用ONNX Runtime加载推理。YOLOv8训练完成后,可以用官方提供的yolo export命令直接导出ONNX,命令类似:
yolo export model=best.pt format=onnx opset=12 dynamic=False几个参数值得细说。opset版本不建议设得太新,工业现场的推理环境往往比较陈旧,opset 12基本兼容主流ONNX Runtime版本,用太新反而容易遇到算子不支持。dynamic=False固定输入尺寸,如果你部署时输入是640x640,导出时就固定为640x640,这样推理速度最快。如果必须支持动态尺寸,dynamic=True会让模型更灵活,但也会略微增加推理延迟和内存占用,工业场景默认不建议。
导出后记得用onnxsim工具做一次计算图简化,把很多冗余节点删掉。同一套模型,简化前后在CPU上的推理速度差个10%~20%很正常。实测下来简化后推理速度快了约15%,这个优化几乎零成本,强烈建议做。
5.2 C++推理框架的集成要点
如果部署端是C++,推荐直接用ONNX Runtime C++ API,它能最大化兼容ONNX模型,省去很多模型转换的麻烦。整体流程是:
- 读取图片,用OpenCV的
imread读取为cv::Mat。 - 预处理:做letterbox,将原图等比缩放到640x640,多余部分用灰色填充。这一步和训练时的预处理必须完全一致,否则坐标映射会错位。
- 归一化:将BGR转为RGB,再除以255.0,转成浮点,维度从HWC转成CHW,最后扩展出batch维度。
- 推理:
session.Run()输出检测结果,通常是三个输出张量(YOLOv8的格式),包含每个候选框的位置、置信度和类别概率。 - 后处理:解码这些候选框,做NMS(非极大值抑制)过滤重叠框。
- 坐标映射:把640x640坐标系还原回输入图片原始尺寸,画框、输出结果。
C++后处理里最常出的问题是letterbox的offset忘记减掉。如果输入图片是1080P,letterbox缩放后填充了上下黑边,推理出的框坐标是640坐标系下的。回归到原图时,必须先减去黑边高度,再除以缩放比例,否则框会整体偏移。这个错我调试了整整一个下午才定位到,经验分享出来,希望大家别踩同样的坑。
5.3 工业现场部署的硬件与性能考量
实际部署硬件我用过NVIDIA Jetson Orin Nano,也用过纯CPU的工控机,两者差异很大。Jetson上可以启用TensorRT加速,ONNX转TensorRT后推理速度能从几十毫秒降到十几毫秒。纯CPU环境下,Intel i5工控机处理640x640输入大约需要30~50毫秒,如果现场摄像头路数较多,需要把推理改成多线程或队列模式,避免两路画面抢同一个推理资源导致阻塞。
夜间场景如果在部署时用到红外模式,建议推理前对图像做一次简单的降噪处理,比如高斯滤波或非局部均值降噪。红外画面噪点相对明显,噪点容易被模型误认为小目标,产生较多误检框。降噪会轻微损失细节,但对防止误报的效果非常显著,现场实测误报数量下降了一半以上。
6. 常见问题与排查技巧实录
6.1 标注坐标错乱或文件缺失
最典型的报错是训练时提示找不到对应图片或标签文件,比如images文件夹里有000123.jpg,但labels里没有000123.txt。这种问题多半是转换脚本漏掉了空XML文件导致的。我写过一个专门的校验函数,遍历images目录下所有图片,检查对应的TXT文件是否存在、文件内容是否为空、坐标数值是否都在0~1之间。建议在数据集制作完成后必跑一遍,避免训练到一半才发现问题。排查方法很简单:在训练脚本里加一段数据完整性检查,发现问题直接终止并打印缺失文件的清单。
6.2 小目标漏检严重
如果模型对远距离或小目标老鼠几乎不响应,首先查看训练时的图像缩放尺寸是不是太小。640x640输入下,一只在画面中只占30x20像素的老鼠,缩放到640后再下采样,特征图上的信息已经非常寥寥。可以考虑加大输入尺寸到1280x1280(如果显存允许),或者使用SAHI这类切片推理工具,把大图切块后再推理,最后合并结果。另外,数据层面可以适当增加小目标样本的复制粘贴增强,把一些清晰的小目标抠出来,以不同尺度粘贴到其他背景图上,能显著提高小目标召回率。实测用这个方法,小目标类别的Recall从0.67提升到了0.81,效果非常直接。
6.3 误检多出现在相似纹理区域
有客户反馈模型把拖把、黑色塑料袋、卷起的电线都误检成老鼠。分析后发现,这些误检目标有三个共同点:颜色暗、纹理杂乱、形状接近团状。常规办法是增加负样本,专门采集这些物体的图片,放入训练集作为背景图(不标目标),让模型学习到“这些是背景”。如果没有足够负样本,另一个思路是调高置信度阈值并设置类别过滤规则,比如在结果后处理阶段把短边小于15像素的框直接丢弃。按实际项目经验,小目标误检占了误检总数很大比例,这个过滤规则设置后误检率下降非常明显。
我个人的经验是,这类问题最好在数据层面解决,不要指望调阈值一劳永逸。每补充一批负样本数据后重新训练,误检情况都会显著改善,而且不会带来召回率下降的副作用。对工业项目来说,宁可多花两天时间整理负样本,也不要上线后再反复调试模型参数。
6.4 不同相机色彩差异造成的性能下降
工厂不同区域可能装了不同品牌的摄像头,色彩风格差异很大,有的偏绿、有的偏黄。同一个模型在一个相机上检测效果很好,换一个相机就出现大量漏检。解决办法是在训练集里加入一些跨相机的色彩扰动样本,或者对每个相机的画面做白平衡校正。最省力的做法是做一个简单的色彩归一化预处理,把三通道均值对齐到参考值。不用做特别复杂,简单的线性校就足够。这个方法解决了我们在一个项目里三台不同品牌相机性能差异悬殊的问题,而且基本没有工程成本,强烈建议数据集里就提前考虑相机多样性。
最后再分享一个小技巧:整套数据集无论是直接训练还是做迁移学习,都建议先跑一个小的sub-training,比如只拿500张图训练50个epoch,验证一下数据管道、标签质量、坐标映射都没有问题之后,再上全量数据训练。这个预跑过程能节省大量排查bug的时间,尤其是团队协作、数据在多人之间流转的情况下,提前暴露问题永远比训练跑到一半才发现好得多。
本文还有配套的精品资源,点击获取