简介:面向目标检测与计算机视觉训练的数据集资源,提供约587张鼠类实景图片及对应标注文件,适合学习YOLO、SSD、Faster R-CNN等检测模型的研究者,也适用于算法验证、模型评估与科研实验。压缩包共1762个文件,包括587张jpg原图、587个xml标注、588个txt标注,整体约149.16MB;图片为jpg格式,单张大小约1-500KB,兼顾清晰度与训练加载效率。数据集同时输出VOC与YOLO两种通用格式,类别统一为rat,由labelImg工具按“准确框选目标边界、完整标注所有目标、交叉检查一致性”的标准制作,压缩包内含三个独立文件夹,分别存放图片、xml标注与txt标注,解压后即可直接查看或接入训练脚本,省去自行转换格式与清洗数据的时间。目前已吸引146人学习下载,既适合初学者练习标注规范与检测流程,也为有鼠类检测需求的项目提供可直接使用的样本集,方便开展模型训练、精度对比与数据增强等实验。
1. 鼠类目标检测数据集落地:587张标注图怎么用才不翻车
做过目标检测的人都知道,模型跑不跑得动,一半看算法一半看数据。这份鼠数据集(rat_20220311 系列,共587张左右JPG图片及配套XML/TXT标注)的价值在于同时提供了VOC和YOLO两种格式,解压即用,不需要自己写转换脚本。适合正在做鼠类识别、实验室动物行为分析、有害生物监测这类场景的开发者,或者刚入门目标检测、想找一份干净数据集练手的人。全文我会从格式差异、目录结构、实际使用、常见坑到验证方法一条线拆完,尽量把参数和操作细节都交代清楚。
2. 理解VOC和YOLO标注格式:坐标体系差异与适用场景
2.1 两种格式的数据结构差异
Pascal VOC格式的标注文件是XML,每个文件对应一张图片,标注信息嵌套在<object>节点里。核心标签包括<name>(类别名)、<bndbox>(边界框)、<xmin>/<ymin>/<xmax>/<ymax>(左上角和右下角坐标)。坐标值是绝对像素值,基于图片原始尺寸计算。
<annotation> <folder>JPEGImages</folder> <filename>rat_20220311_47.jpg</filename> <size> <width>640</width> <height>480</height> <depth>3</depth> </size> <object> <name>rat</name> <bndbox> <xmin>120</xmin> <ymin>80</ymin> <xmax>350</xmax> <ymax>300</ymax> </bndbox> </object> </annotation>逻辑说明:VOC格式的XML解析核心在于遍历所有<object>节点,读取<name>和<bndbox>内的四个坐标值。参数说明:<width>和<height>必须和实际图片像素一致,否则等下转YOLO格式或者训练时会出大问题。这份数据集既然官方提供了导出后的TXT,理论上XML和图片是匹配的,但实际用的时候我还是建议抽几张核对一下。
YOLO格式的标注文件是TXT,每行对应一个目标,格式为class x_center y_center width height,所有值都是相对图片宽高的归一化比例,取值范围0到1。类别要从单独的classes.txt文件读取,该文件每行一个类别名,这份数据集只有rat一个类。
0 0.3671875 0.3958333 0.3593750 0.4583333逻辑说明:上面例子对应x_center=0.367、y_center=0.396、width=0.359、height=0.458,是归一化后的值。参数说明:假设图片宽640高480,反推回去就是 xmin=0.367×640 - (0.359×640)/2 ≈ 120,和前面VOC的xmin对得上。这种格式的意义在于不依赖图片绝对尺寸,同一标注文件可适配不同分辨率的输入,模型训练时只需关心相对位置和大小比例。
2.2 选型时为什么要同时提供两种格式
很多目标检测框架默认只吃一种格式。YOLO系列(v5/v8等)官方训练脚本直接用TXT格式,而老牌框架或部分自定义训练脚本读VOC更顺手。同时提供两份意味着你不用花时间在格式转换上,也不存在转换精度损失。
我一般会按这个逻辑做选型判断:
- 用Ultralytics YOLOv8训练,直接指向TXT文件夹 + data.yaml,类别写
names: ['rat']。 - 用MMDetection或Detectron2,它们的标准数据集格式是COCO,但都提供了VOC转COCO的脚本工具,用这份XML就能转。
- 如果你要做标注质量审计,看VOC的XML比看YOLO的TXT直观得多,直接撕开XML里的坐标比对原图。
一句话结论:TXT是训练主流,XML是审计和转换的源头。两份都在手里,你才不会被某个特定训练框架绑定住。
3. 映射到YOLOv8训练:目录重排与配置文件实战
3.1 把压缩包结构重排为YOLO训练标准目录
拿到压缩包解压后,里面有图片文件夹、XML文件夹、TXT文件夹三个部分。YOLOv8官方训练脚本期望的目录结构通常是images/train、labels/train这种按用途分开的布局。你需要做一次映射,不需要改文件名,只调整目录归属。
# 假设解压后三个目录为:jpg、xml、txt mkdir -p dataset/rat/images/train dataset/rat/images/val mkdir -p dataset/rat/labels/train dataset/rat/labels/val mkdir -p dataset/rat/xmls/train dataset/rat/xmls/val # 把图片复制到统一目录,后续用脚本按比例切分 cp jpg/*.jpg dataset/rat/images/train/ cp txt/*.txt dataset/rat/labels/train/ cp xml/*.xml dataset/rat/xmls/train/逻辑说明:先建立YOLO需要的目录骨架,然后全部先放进train目录,再用脚本抽出一部分做验证集。参数说明:587张图建议验证集取80到120张,不要太多也不要太少,太少评估结果波动大,太多训练数据损失明显。这一步纯属文件搬运,不涉及内容修改。
3.2 用脚本按比例切分训练集和验证集
import os import random import shutil random.seed(42) image_dir = "dataset/rat/images/train" label_dir = "dataset/rat/labels/train" val_image_dir = "dataset/rat/images/val" val_label_dir = "dataset/rat/labels/val" images = [f for f in os.listdir(image_dir) if f.endswith(".jpg")] random.shuffle(images) val_count = int(len(images) * 0.15) # 约88张 val_images = images[:val_count] for img in val_images: shutil.move(os.path.join(image_dir, img), os.path.join(val_image_dir, img)) label_name = img.replace(".jpg", ".txt") shutil.move(os.path.join(label_dir, label_name), os.path.join(val_label_dir, label_name))逻辑说明:这段脚本先列出所有图片,固定随机种子保证切分结果可复现,再把15%的图片及其同名TXT一起移动到验证集目录。参数说明:seed=42确保每次执行结果一致,不至于两次跑出来训练集不同;val_count按总图数的整数比例计算,587×0.15≈88,对小型数据集来说这个比例合理。如果之后发现验证集里某类目标太少,可以调高比例到0.2,但低于0.1的话评估结果会很不稳定。
3.3 编写data.yaml配置并启动训练
# dataset/rat/data.yaml train: dataset/rat/images/train val: dataset/rat/images/val nc: 1 names: ['rat']yolo detect train \ model=yolov8s.pt \ data=dataset/rat/data.yaml \ epochs=100 \ imgsz=640 \ batch=16 \ patience=20逻辑说明:data.yaml里的路径可以是相对路径也可以是绝对路径,Ultralytics脚本要求必须写实际存在的目录,nc: 1对应只有一个类别。训练命令中model=yolov8s.pt会在首次运行时自动下载预训练权重,imgsz=640是标准输入尺寸,patience=20是早停容忍度,连续20轮验证集指标不提升就自动停止。参数说明:如果你的显卡显存有限,降低batch到8或4;如果图片本身就小于640,比如这份数据里有300×200的图,Ultralytics会自动做letterbox填充,不影响训练。
4. 避坑与排查:解压后最容易踩的五个实际问题
4.1 标注框与目标边缘贴合度差
现象:可视化检查时发现有的框偏大,把背景也包进去了。
原因:labelImg手工标注时,如果标注者着急或者图片模糊,很容易出现框边缘留白过多。
解决:不要急着训练,先用可视化脚本把所有标注框画出来叠加到原图上快速过一遍。耗时半小时能发现的问题,不要留到训练完再去评估,返工成本高得多。
4.2 图片含EXIF信息可能导致方向错乱
现象:JPG原图在查看器里显示正常,但训练后预测结果总偏90度或180度。
原因:部分手机或相机拍摄的图片在EXIF里写入了旋转方向信息,某些库读取像素时没有自动应用该旋转。
解决:建议在训练前统一用工具清洗一遍,把方向信息固化为实际像素排列。这个步骤是可选防御性操作,因病理性原因并不普遍。
4.3 XML和TXT存在潜在不一致
现象:同一图片的XML坐标和TXT坐标反推出来的边界框对不上。
原因:两份文件如果不是一次性导出的完整结果,或者中间有过人为修改其中一份,就会漂移。
解决:写个脚本遍历所有XML和TXT,各算一次目标数和框坐标做交叉比对,不一致的文件直接单独挑出来人工核查。这个项目类目单一,理论上不会有太大偏差,但如果发现也会直接暴露问题。
4.4 数据增强导致标注失效
现象:训练时用了Mosaic和RandomAffine增强,模型效果反而下降了。
原因:增强操作会对图片做拼接、旋转、缩放,但如果图片是长条形或者目标在边缘,有些增强方式会把目标严重截断甚至完全切出画面,相当于每轮都在学习噪音。
解决:不要上来就开满全套增强。先用mosaic=0.0、degrees=0跑一轮baseline,确认没问题再加回来。特别是像鼠这类目标占比不大且常常贴边的图片,保守的增强策略更稳。
4.5 GPU显存不足和线程阻塞
现象:训练报CUDA out of memory,或者数据加载慢吞吞。
原因:batch设太大、图片尺寸可能被拉得过高,加上数据加载线程数量不足或磁盘IO跟不上。
解决:显存不够先降batch,再不行降imgsz到480;数据加载慢就调大workers,Windows上通常设2到4就行,Linux可以到8,跑之前确认磁盘不是机械硬盘瓶颈。
5. 训练前必须做的三件事:可视化验证、一致性校验和类别确认
5.1 可视化叠加标注框检查
这是我认为最重要的习惯,永远不等训练完才去检查标注质量。写一个脚本直接把XML坐标画到原图上:
import cv2 import xml.etree.ElementTree as ET def draw_voc_boxes(image_path, xml_path): img = cv2.imread(image_path) tree = ET.parse(xml_path) root = tree.getroot() for obj in root.iter('object'): name = obj.find('name').text 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) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2) cv2.putText(img, name, (xmin, ymin - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) return img result = draw_voc_boxes("rat_20220311_47.jpg", "rat_20220311_47.xml") cv2.imwrite("check_47.jpg", result)逻辑说明:这段脚本会读取XML中每个object的坐标并在图片上画框,同时标注类别名,输出一张可直接肉眼检查的验证图。参数说明:绿色框是边界框,红色文字是类别名,如果你发现绿色框明显包住整个背景甚至只框到老鼠的半截身体,这张图对应的标注就要修。
5.2 批量扫描标记缺失和空标签
import os def check_missing_labels(image_dir, label_dir, ext=".txt"): missing = [] empty = [] for f in os.listdir(image_dir): if not f.endswith(".jpg"): continue label_path = os.path.join(label_dir, f.replace(".jpg", ext)) if not os.path.exists(label_path): missing.append(f) continue if os.path.getsize(label_path) == 0: empty.append(f) print("missing:", missing) print("empty:", empty) check_missing_labels("dataset/rat/images/train", "dataset/rat/labels/train")逻辑说明:目标检测里最可疑的情况不是框画歪,而是漏标——整张图片没有标注文件,或标注文件是空文件。这两类数据如果混进训练集,模型会直接学到“这个场景没有目标”,严重污染训练信号。参数说明:ext参数默认".txt",如果检查XML就把后缀改成.xml,脚本逻辑不变。
5.3 与yaml类别确认一致
注意一个细节:如果labelImg导出时定义了多个类别,比如把鼠和背景杂物都框了,那TXT里的类别索引可能不止0。你需要扫一遍所有TXT文件,看看行首的数字都有哪些,确保和data.yaml里的names一一对应。
cut -d' ' -f1 dataset/rat/labels/train/*.txt | sort -u这条命令会把所有训练集TXT文件的第一列(类别索引)全部捞出来去重排序,正常情况下输出应该只有1一个数字。如果出现了其他索引,说明这份数据集中混入了其他类别标注,这时候必须决定是删掉这些文件还是扩展names列表。从那以后我每次换数据集,都会强制走一遍这三步,不跳过。要么不动手训练,要动手就先过这三关。这个习惯帮我拦下了至少三次灾难性训练,希望帮到你。
本文还有配套的精品资源,点击获取