简介这份鼠类检测数据集面向目标检测与计算机视觉研究者整理约587张真实鼠类jpg图片全部使用labelImg完成标注类别统一为rat。格式上同时提供VOC与YOLO两种主流标注方案压缩包内分为图片、xml标注、txt标注三个文件夹解压后无需额外配置即可接入YOLO系列、Faster R-CNN等检测框架适合快速完成模型训练、验证或算法对比也便于入门练习与科研复现。资源包共1762个文件包括587张jpg图片、587个xml标注文件、588个txt标注文件及少量辅助文件整体大小149.16MB图片单张1-500KB兼顾清晰度与加载效率。压缩包为rar格式无需解压密码解压后即可查看目录结构与对应标注。标注过程强调边界准确、目标不遗漏并通过交叉检查保证一致性标签质量较为可靠。目前已有146人浏览学习可直接作为现成的双格式鼠类数据集使用省去自行采集、清洗和标注的大量时间。1. 鼠数据集VOC和yolo格式目标标注587张左右一份能直接喂给YOLO的标注资产做目标检测的人手里最缺的不是模型是一份干净的、格式统一的标注数据。这个标题给的就是这样一份东西鼠数据集587张左右图像同时提供VOCXML和YOLOTXT两种目标标注格式。这意味着你拿到的不是一张图片列表而是一套可以直接进入训练流程的资产——用VOC格式做编辑、校对、二次标注用YOLO格式直接跑yolov8或者更早的yolov5训练中间省掉最脏最累的格式转换环节。适合谁做行为学实验视频分析的、做实验室监控鼠只识别的、以及任何需要在封闭场景里检测小目标的新手项目。587张不算大但对于鼠类这种目标类别单一、场景相对固定的任务配合数据增强完全够把模型训起来。2. 先定目录再动手VOC与YOLO双格式的目录结构和标注规范2.1 双格式的目录结构长什么样拿到这份数据集时先别急着打开图片看内容第一件事是确认目录结构是否符合约定俗成的标准。VOC格式的目录结构源自PASCAL VOC比赛常见做法是数据集根目录下分三个子目录JPEGImages存放原始图像Annotations存放每张图对应的XML标注文件ImageSets/Main存放训练集、验证集、测试集的划分文件通常是train.txt、val.txt、trainval.txt。YOLO格式目录结构不同它的标签是纯文本TXT文件每行一条目标记录存放在labels目录下且TXT文件名必须与图片文件名完全一致只是扩展名不同。dataset_root/ ├── VOC/ │ ├── JPEGImages/ # 所有原始图像 │ ├── Annotations/ # 每张图对应的XML标注 │ └── ImageSets/ │ └── Main/ # train.txt, val.txt, test.txt ├── YOLO/ │ ├── images/ # 图像或直接用软链接指向JPEGImages │ └── labels/ # 每张图对应的TXT标注 ├── classes.txt # 类别列表一行一个类名 └── data.yaml # YOLO训练配置文件这个结构是底线。yolov8训练时读取的是data.yaml里指定的train和val路径同时根据names字段去解析labels里的类别编号。如果labels里的TXT文件和images里的图片文件名对不上训练时loss照算但mAP会莫名其妙地低甚至出现unable to find label file警告。标题里既然标注了VOC和YOLO双格式就应该同时满足两套目录规范。2.2 XML标注字段逐项说明name、bndbox、difficult哪个会坑你打开任一张图的XML标注大概长这样字段不多但每个都有讲究annotation folderJPEGImages/folder filenamemouse_001.jpg/filename path/home/user/dataset/VOC/JPEGImages/mouse_001.jpg/path source databaseUnknown/database /source size width1920/width height1080/height depth3/depth /size segmented0/segmented object namemouse/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin452/xmin ymin234/ymin xmax1387/xmax ymax891/ymax /bndbox /object /annotationsize里的width和height是训练时做坐标归一化的基准如果这里填错转换出来的YOLO坐标全部作废。object里可以出现多次代表一张图有多个目标。最容易被忽略的是difficult字段——在PASCAL VOC的评测体系里difficult为1的目标不参与mAP计算但在YOLO的TXT格式里没有对应字段转换时要么丢弃要么当普通目标保留。对鼠数据集这种场景我一般建议difficult1直接丢弃因为标注者标了difficult说明目标本身模糊不清保留下来只会干扰模型收敛。truncated表示目标是否在图像边缘被截断。这个字段YOLO也不认但转换时可以做一个判断如果truncated1且目标被截断面积超过一定比例就跳过DP。不过587张左右的数据集里这种极端情况应该不多不用太纠结。2.3 标完先跑一遍XML完整性检查标注工作完成后第一件事是检查XML和图片的对应关系。常见问题有XML文件存在但对应图片缺失、图片存在但XML没标注、XML里size字段和实际图片尺寸不一致。写一个简单的检查脚本能在半小时内把问题全暴露出来比等训练到一半才报错强得多。import os import xml.etree.ElementTree as ET from PIL import Image jpeg_dir VOC/JPEGImages ann_dir VOC/Annotations jpeg_files {f.split(.)[0] for f in os.listdir(jpeg_dir)} ann_files {f.split(.)[0] for f in os.listdir(ann_dir)} # 检查1文件名一一对应 print(XML无对应图片:, ann_files - jpeg_files) print(图片无对应XML:, jpeg_files - ann_files) # 检查2XML内size字段与真实图片尺寸比对 for name in jpeg_files ann_files: xml_path os.path.join(ann_dir, name .xml) img_path os.path.join(jpeg_dir, name .jpg) img Image.open(img_path) w, h img.size tree ET.parse(xml_path) root tree.getroot() xw int(root.find(size/width).text) xh int(root.find(size/height).text) if (w, h) ! (xw, xh): print(f{name}: XML({xw},{xh}) vs 实际({w},{h}))这段脚本干了两件事文件对账和尺寸对账。第一件事检查有没有孤儿XML或孤儿图片第二件事用一种不够优雅但足够直观的方式检查XML里记录的尺寸和真实图片是否一致。实际项目中我还会加第三步遍历每个XML里的bndbox坐标判断xmin xmax、ymin ymax、坐标不超出图像边界。这一步可以并进避坑章节里细说这里先知道有这回事。运行后重点看输出里有没有XML无对应图片或尺寸不一致的记录。VOC格式最坑的地方在于XML里写错尺寸不会报错训练时照样跑但YOLO坐标归一化后全是错的模型收敛了也白训。3. 把VOC转成YOLO格式转换脚本与四个边界坑3.1 转换公式不是x/w那么简单VOC的bndbox记录的是左上角和右下角的绝对像素坐标(xmin, ymin, xmax, ymax)YOLO格式需要的是归一化后的中心点坐标和宽高(center_x, center_y, width, height)四个值都除以图片宽度和高度。对应的转换公式是center_x (xmin xmax) / 2 / widthcenter_y (ymin ymax) / 2 / heightbox_w (xmax - xmin) / widthbox_h (ymax - ymin) / height。注意分子上的除以2是先求中心点的像素坐标再做归一化。顺序不能反也别想着合并成一个式子写清楚每一步后面排查问题会很方便。这里存在一个很多人容易忽略的细节width和height应该取什么值答案是取XML里size字段记录的width和height。如果之前做过校验这个值和真实图片一致那么用哪个都行如果没做过校验请用真实图片尺寸也就是用PIL读出来的结果。3.2 完整转换脚本与逐行说明import os import xml.etree.ElementTree as ET from PIL import Image def convert_voc_to_yolo(xml_path, img_path, class_list, output_txt_path): 将单个VOC XML标注转换为YOLO TXT标注 class_list: 类别列表, [mouse] # 读取真实图片尺寸确保归一化基准准确 img Image.open(img_path) img_w, img_h img.size tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text # 跳过未在类别列表中的目标 if name not in class_list: continue # 跳过difficult1的目标按需取舍 difficult obj.find(difficult).text if int(difficult) 1: continue class_id class_list.index(name) bndbox obj.find(bndbox) xmin int(bndbox.find(xmin).text) ymin int(bndbox.find(ymin).text) xmax int(bndbox.find(xmax).text) ymax int(bndbox.find(ymax).text) # 边界安全检查坐标必须合法 if xmin xmax or ymin ymax: print(fSkipped invalid box in {xml_path}: ({xmin}, {ymin}, {xmax}, {ymax})) continue # 归一化中心点与宽高 center_x ((xmin xmax) / 2) / img_w center_y ((ymin ymax) / 2) / img_h box_w (xmax - xmin) / img_w box_h (ymax - ymin) / img_h # 限制浮点数位数避免训练时解析报错 lines.append(f{class_id} {center_x:.6f} {center_y:.6f} {box_w:.6f} {box_h:.6f}) with open(output_txt_path, w, encodingutf-8) as f: f.write(\n.join(lines))这段代码有四个关键设计。第一用真实图片尺寸做归一化不用XML里的size去掉一个不可控变量。第二跳过difficult1的目标这里用continue而不是break因为同一张图可能有多个目标一个difficult不等于整张图都该跳过。第三坐标合法检查拦住了xminxmax这种退化框——这种情况常见于标注时手滑中心点和宽高算出来有一项是0YOLO训练时BN层直接崩。第四格式化输出保留6位小数不需要更多精度够了还省磁盘空间。调用方式是遍历整个VOC的Annotations目录对每个XML走一遍转换输出到YOLO/labels目录下。转换完成后classes.txt里写一行mousedata.yaml里names: [mouse]。注意class_id的顺序必须和classes.txt一致一旦排好序就不要再动不然后面训练时所有类别标签全错位。3.3 转换后验证labels里不该出现什么转换完成不代表转换正确。打开几个TXT文件看看每行应该是类别编号 浮点数 浮点数 浮点数 浮点数的格式前两个浮点数应该都在0到1之间表示中心点归一化坐标后两个浮点数表示归一化宽高理论上也在0到1之间。以下是我在验证时重点检查的几种情况大家可以直接参考中心点越界中心点坐标出现小于0或大于1的值说明bndbox的坐标本身就超出了图片范围。多见于标注时没仔细看把框拖到了图片边界外面。解决方法是回VOC的XML里把对应目标的bndbox改到图片范围内然后重新转换。宽高为0某一行的第四个或第五个浮点数是0.000000这是退化的单点框。训练时这类目标对应的特征图位置没有实际面积损失计算会出现NaN。解决方法是脚本里已经加了xmin xmax的判断如果还是出现了0说明xml里记录的是浮点数值而代码里用了int转换把值截断了检查一下是不是有小数坐标。类别编号越界TXT第一列数字大于等于类别总数比如只有mouse一个类别但出现了1或2说明XML里存在没见过的目标名。常见的处理是先前确认了这类目标算不算误标不算就加回class_list算就删掉对应的object块。4. 587张小数据集的训练验证与数据增强4.1 先按9:1切分训练集别再做验证集587张左右的数据量不小但也不算大切分策略直接决定你后面说的mAP有没有参考价值。常见做法是按9:1切分训练集和验证集也就是大约528张训练、59张验证。这个比例比较合适验证集太少mAP波动大每次训练结果都像抽奖验证集太多训练数据不够模型学不到位。切分的关键是随机种子固定下来保证每次跑出来的结果可以复现。如果数据里有连续性很强的序列帧比如从视频里抽的帧切分时要注意不能把同一段视频的相邻帧同时分进训练集和验证集否则模型在验证集上的表现会被严重高估。简单做法是先按视频片段分组再对组进行随机切分。对于这份标题里提到鼠数据集由于没有说明数据来源是拍摄的视频帧还是独立采集的图像这里建议拿到数据后先检查文件名是否有序号规律——如果像mouse_001.jpg到mouse_587.jpg这样连续编号就需要手动确认是否来自视频抽帧再做分组切分。4.2 小数据集翻车现场不调参直接训loss到0.05但mAP为0小数据集最典型的表现是过拟合而且过拟合的伪装性很强训练集loss一路下降到0.05以下验证集loss先降后升最终mAP停在0附近。这个现象在你第一次训练时几乎必现原因主要有两个方向一个是数据量本身太少模型把训练集的背景纹理记住了而不是学会识别鼠本身另一个是标注中存在不一致这里最典型的例子是有人把笼子里另一只鼠的局部阴影也框进去了导致正样本里混入噪声。两者表现都是loss降了但mAP上不去。解决方式有两种路径。第一条路径是先做数据增强把587张的有效信息量撑大第二条路径是直接用短训练轮数配合早停把过拟合问题暴露出来然后再针对性补充数据或者增强。两种路径不冲突先做增强再开patience30的早停观察验证集mAP曲线。4.3 用yolov8跑通最小训练命令把data.yaml准备好之后训练命令很短yolo detect train datadata.yaml modelyolov8n.pt epochs100 imgsz640 batch8 patience20 project./runs namemouse_exp这是够用的最小命令参数含义如下modelyolov8n.pt用nano版本起步训练速度快内存占用低适合试错epochs100对小数据集来说已经完全够用再多大概率过拟合imgsz640保持YOLO系默认输入尺寸batch8取决于显存大小如果显存是8G以下就改成4patience20是早停轮数验证集mAP连续20轮不涨就停。训练完成后去看runs/mouse_exp/下的results.png重点看val/box_mAP那一条曲线它会告诉你模型真实的泛化水平正确评估模型效果的关键参考。有一个值得留意的地方是单独一次训练在小数据集上的mAP波动可能非常大同样的数据重训一遍结果可能差好几个点。所以不要用一次训练的结果下结论至少要跑三次取平均。5. 避坑鼠数据集标注与转换的5个常见问题5.1 XML坐标超出图片边界现象YOLO训练时日志出现大量警告类似WARNING: non-intersecting box detected或者loss出现NaN验证集mAP极低。原因VOC标注阶段把目标框拖出了图片边界XML里的xmax或ymax大于图片实际宽高。转换脚本没有做clip操作归一化后中心点坐标超过1。解决转换前遍历XML对bndbox做一次坐标裁剪把超出图片范围的值修正到边界上。注意只修正值本身不改变目标尺寸。修正后重新转换。5.2 归一化后宽高为0目标框变成了一条线现象labels文件夹里某些TXT文件某一行是0 0.5214 0.4021 0.000000 0.0833第四个字段或者第五个字段为0。原因bndbox的xmin等于xmax或者ymin等于ymax。常见于标注小目标时鼠标双击自动闭合框退化成了线。训练时这种目标不产生有效特征还会拉偏损失函数计算。解决转换脚本里加判断xmin xmax或ymin ymax的直接跳过或修正。我的建议是跳过并打印文件名人工检查这张图是否需要重新标注。5.3 类别编号与classes.txt错位现象训练和验证时loss正常下降但预测阶段发现检测结果是错的例如标注为mouse的目标预测出来是rat或者其他完全无关的类别。原因自己手动整理classes.txt时把类别顺序改了但YOLO标签里的类别编号还停留在转换时的顺序。也可能是多个数据集合并时不同数据集的类别表冲突了。解决锁定classes.txt的行顺序任何情况下不要修改。新增类别只追加到末尾不做中间插入。合并数据集前先统一类别表再重新生成所有TXT标签。5.4 图片路径带中文或空格导致训练中断现象yolov8训练启动时报错提示找不到图片文件但路径明明存在。原因Windows环境下数据集放在中文目录比如D:\用户\数据集\鼠\...或者文件名本身带空格。OpenCV和Ultralytics的部分依赖对非ASCII路径支持不完善。解决整个项目目录全部改成英文小写加下划线例如/home/user/rodent_dataset/。文件重命名后同步修改XML里的filename和path字段。5.5 标注文件中出现空TXT文件现象训练时出现空标签警告或者验证时部分图片的mAP计算为0。原因某些图片确实没有任何目标可见比如空笼取样转换脚本写入空字符串生成0字节TXT文件。YOLO训练时对这种文件报警告但不报错容易忽略问题。解决转换后清理labels目录把0字节文件对应的图片移出训练集或者在data.yaml的train和val路径中不包含这批图片。587张的数据如果出现十来个空标注说明采集时机有偏差建议回看原始图像确认这些帧是否真的没有鼠只活动。6. 画框回显验证标注质量的一个自查技巧标注质量验证最直观的手段是回显画框把TXT标签的可视化结果叠加在图像上逐一翻看。常见做法是写一个简单的OpenCV脚本读取TXT里的坐标和类别编号在图上画矩形框和类别名批量输出到check/目录。脚本逻辑很简单不用做大而全的可视化工具重点是你翻看那587张图时能发现哪些框松了、哪些框偏了、哪些框把尾巴或者阴影也算进去了。这一步某种意义上属于数据清洗的后悔药问题发现得越早返工成本越低。import cv2 import os img_dir YOLO/images label_dir YOLO/labels out_dir check os.makedirs(out_dir, exist_okTrue) class_names [mouse] # 与classes.txt保持一致 for img_name in os.listdir(img_dir): stem os.path.splitext(img_name)[0] img cv2.imread(os.path.join(img_dir, img_name)) h, w img.shape[:2] txt_path os.path.join(label_dir, stem .txt) if not os.path.exists(txt_path): continue with open(txt_path) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue cls_id int(parts[0]) cx, cy, bw, bh map(float, parts[1:]) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, class_names[cls_id], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imwrite(os.path.join(out_dir, img_name), img)这个脚本会把YOLO格式的归一化坐标还原成像素坐标并画框。翻看时盯两件事框是否紧贴目标轮廓框是否覆盖到了目标的一部分。鼠类目标往往姿态多变蜷缩时和伸展时形状差异很大标注框的松紧度如果不一致模型在预测阶段会很难找准边界。如果大部分框都偏大或偏小批量修正的方法是重写XML里的bndbox再走一遍转换流程不要直接在TXT上改。数据增强在小数据集上的应用要克制。翻转、旋转、亮度扰动这些基础操作对鼠数据集有效但幅度要控制好——90度旋转对鼠这种有头尾朝向的目标会破坏方向信息你翻车一次就知道定向任务里mosaic过强反而掉点。我的做法是先看回显结果人工判断哪些框最有信心用yolov8自带的augment参数原地增强不开额外离线生成。587张的数据配合在线增强已经能训出一个够用的检测模型。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?