news 2026/10/1 20:33:57

370张鹅数据集VOC与YOLO格式标注及小样本检测实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
370张鹅数据集VOC与YOLO格式标注及小样本检测实战

简介:本资源为一份面向目标检测学习者的鹅类图像数据集,采用VOC与YOLO双格式标注,适合从事禽类识别、农业智能化或计算机视觉入门实践的开发者与研究人员使用。压缩包共1111个文件,包含370张jpg图片、370个xml标注文件与371个txt标注文件,整体约26.82MB,rar格式无需解压密码,解压后图片与标注分文件夹存放,可直接导入labelImg或主流检测框架查看与训练。所有图片均由labelImg人工标注,类别统一为goose,标注过程遵循边界框选准确、目标尽量不遗漏、完成后交叉一致性检查等原则,标注质量较为可靠。目前已有85人学习关注,可作为鹅类检测模型训练、格式转换练习或小样本实验的基础数据,帮助读者省去自行采集与标注的时间成本,快速投入模型搭建与验证工作。

1. 鹅数据集 VOC 和 YOLO 格式目标标注 370 张:小样本检测到底能不能打

手里只有 370 张鹅的图片,标注还分 VOC 和 YOLO 两套格式,这事放在目标检测项目里属于典型的“小样本起步”。很多做养殖巡检、鹅群计数、行为分析的朋友,第一步就卡在数据上:公开数据集里鹅的样本少,自己拍又拍不了几千张,标注工具换一个格式就乱一次。这个标题讲的就是这么一件具体的事——370 张鹅图,同时提供 VOC 的 XML 和 YOLO 的 TXT 两套标注,怎么把它们用起来、怎么训、训出来能不能用。

适合谁看:手头有几百张自采图、想跑通鹅目标检测的工程同学;需要把 VOC 标注迁到 YOLO 训练管线的人;以及想评估“这个量级的数据值不值得投入”的决策者。370 张不算多,但也不是玩具级,关键看你怎么切分、怎么增强、怎么选预训练权重。下面按“先搞懂格式差异 → 再动手转换和训练 → 最后说坑和进阶”的顺序讲,能直接抄的步骤我都给全。

2. VOC 与 YOLO 标注格式的差异与转换:从 XML 到 TXT 的完整脚本

2.1 两种格式到底差在哪,为什么不能混着喂给模型

VOC 格式的核心是一个 XML 文件对应一张图,里面用<object>节点记录每个目标的类别和边界框,边界框用xmin/ymin/xmax/ymax四个绝对像素坐标表示。YOLO 格式则是一个 TXT 文件对应一张图,每行一个目标,格式是类别索引 cx cy w h,其中cx cy是归一化后的中心点坐标,w h是归一化后的宽高,全部除以图片的宽和高得到 0 到 1 之间的小数。

这个差异带来的直接后果是:VOC 的坐标跟图片分辨率绑定,换一套图就得重新算;YOLO 的归一化坐标跟分辨率解耦,但类别必须映射成从 0 开始的整数索引。很多人把 VOC 的 XML 直接改后缀当 TXT 用,训练时 loss 不降,排查半天才发现坐标根本没归一化。另一个常见翻车点是类别索引:VOC 里类别是字符串,YOLO 里是整数,如果你的类别列表顺序和生成 TXT 时的顺序不一致,模型学到的就是错位的类别。

提示:转换前先把所有类别名收集全,排好序,生成一个classes.txt,后续训练和推理都依赖这个顺序,别中途改。

2.2 用 Python 把 VOC 批量转成 YOLO 格式

下面这个脚本我用了很多次,输入是 VOC 的Annotations目录和JPEGImages目录,输出是 YOLO 的labels目录和classes.txt。它做了三件事:收集类别、按图片尺寸归一化坐标、跳过没有目标的空标注文件。

import os import xml.etree.ElementTree as ET from PIL import Image # 输入路径 voc_anno_dir = "dataset/Annotations" voc_img_dir = "dataset/JPEGImages" # 输出路径 yolo_label_dir = "dataset/labels" classes_file = "dataset/classes.txt" os.makedirs(yolo_label_dir, exist_ok=True) # 第一步:收集所有类别,排序保证索引稳定 classes = set() for xml_file in os.listdir(voc_anno_dir): if not xml_file.endswith(".xml"): continue tree = ET.parse(os.path.join(voc_anno_dir, xml_file)) for obj in tree.findall("object"): classes.add(obj.find("name").text) classes = sorted(list(classes)) with open(classes_file, "w") as f: f.write("\n".join(classes)) print("类别列表:", classes) # 第二步:逐张转换 for xml_file in os.listdir(voc_anno_dir): if not xml_file.endswith(".xml"): continue tree = ET.parse(os.path.join(voc_anno_dir, xml_file)) root = tree.getroot() # 找到对应图片,读尺寸 img_name = root.find("filename").text img_path = os.path.join(voc_img_dir, img_name) if not os.path.exists(img_path): print("缺图,跳过:", img_name) continue with Image.open(img_path) as im: iw, ih = im.size lines = [] for obj in root.findall("object"): cls_name = obj.find("name").text cls_id = classes.index(cls_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) # 归一化中心点和宽高 cx = (xmin + xmax) / 2.0 / iw cy = (ymin + ymax) / 2.0 / ih w = (xmax - xmin) / iw h = (ymax - ymin) / ih lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}") # 写 TXT,空标注也写空文件,保持一一对应 txt_name = os.path.splitext(xml_file)[0] + ".txt" with open(os.path.join(yolo_label_dir, txt_name), "w") as f: f.write("\n".join(lines)) print("转换完成")

逻辑说明:先遍历所有 XML 收集类别并排序,保证classes.txt的顺序就是索引顺序;然后逐张读图拿宽高,把 VOC 的绝对坐标转成归一化中心点加宽高。参数上,cx cy w h保留 6 位小数足够,YOLO 训练时对精度不敏感。注意空标注文件也要生成,否则训练时图片和标签数量对不上,DataLoader 会报错。

2.3 转换后必须做的三项校验

转换完别急着开训,先做校验,这三项能挡掉八成低级错误。第一项,检查 TXT 行数和 XML 里<object>数量是否一致,不一致说明有目标被漏掉。第二项,随机抽 5 张图,用 OpenCV 把归一化坐标画回原图,肉眼看框是否贴合鹅的身体。第三项,统计每个类别的框数量,如果某个类别只有个位数,训练时基本学不动,得考虑合并类别或补数据。

import cv2 def draw_yolo_box(img_path, label_path, classes): img = cv2.imread(img_path) ih, iw = img.shape[:2] with open(label_path) as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue cls_id, cx, cy, w, h = int(parts[0]), *map(float, parts[1:]) x1 = int((cx - w / 2) * iw) y1 = int((cy - h / 2) * ih) x2 = int((cx + w / 2) * iw) y2 = int((cy + h / 2) * ih) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, classes[cls_id], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imwrite("check_vis.jpg", img) # 用法:draw_yolo_box("dataset/JPEGImages/001.jpg", "dataset/labels/001.txt", classes)

这段代码把归一化坐标还原成像素坐标画框,cx - w/2就是左上角 x,乘回iw得到像素值。跑几张看看,如果框整体偏移或大小不对,回去查归一化时用的图片尺寸是不是和实际图片一致——常见坑是 XML 里记录的size和真实图片尺寸不符,脚本里我直接用 PIL 读真实尺寸,避开了这个雷。

3. 370 张鹅图怎么切分与训练:YOLOv8 最小可跑通流程

3.1 数据集切分比例与目录结构

370 张的切分不能照搬大数据的 8:1:1,那样验证集只有 37 张,指标抖动会很大。我一般按 7:2:1 切,训练 259 张、验证 74 张、测试 37 张。如果类别不平衡严重,改用分层抽样,保证每个类别在验证集里都有出现。目录结构按 YOLOv8 的要求来:

dataset/ images/ train/ val/ test/ labels/ train/ val/ test/ data.yaml

data.yaml里写清楚路径和类别名:

path: ./dataset train: images/train val: images/val test: images/test nc: 1 names: ['goose']

nc是类别数,鹅检测通常就一类,如果还要分“成年鹅/幼鹅”就改成对应数量,names顺序必须和classes.txt一致。

3.2 用预训练权重起步,别从零训

370 张从零训基本没戏,必须用 COCO 预训练的 YOLOv8n 或 YOLOv8s 起步。n 版参数量小,小样本下更不容易过拟合;s 版精度略高但需要更多数据。我的经验是 370 张先用 n 版跑基线,mAP 能到 0.6 以上再考虑换 s 版。训练命令:

yolo detect train \ data=dataset/data.yaml \ model=yolov8n.pt \ epochs=150 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=30 \ augment=True \ project=runs/goose \ name=exp1

参数说明:epochs=150对小数据够用,配合patience=30早停防止过拟合;imgsz=640是 YOLOv8 默认,鹅的体型在图中占比中等,640 够用,如果鹅很小可以提到 960;batch=16看显存,V100 上可以到 32;lr0=0.01是初始学习率,小数据建议降到 0.005 更稳;augment=True开启内置增强,包括马赛克、翻转、HSV 抖动,这对 370 张的扩充很关键。

3.3 训练过程看什么指标,什么时候该停

训练时重点盯三个东西:box_loss是否稳定下降、mAP50是否在涨、验证集 loss 是否开始反弹。前 20 个 epoch loss 下降慢是正常的,预训练权重需要时间适配新数据。如果 50 epoch 后 mAP50 还在 0.1 以下,大概率是标注有问题或类别映射错了,回去查 TXT 文件。如果训练 loss 降但验证 loss 涨,说明过拟合,加增强或减模型容量。混淆矩阵不唯一这种问题在小数据里也常见,通常是验证集样本太少导致,把验证集比例提到 0.25 能缓解。

注意:370 张的验证集只有 70 多张,mAP 波动 ±0.05 都算正常,别因为一个 epoch 掉了就调参,看趋势。

4. 小样本鹅检测的避坑与排查:5 个血泪教训

4.1 现象:训练 loss 不降,mAP 始终为 0

原因:最常见的是类别索引错位。VOC 转 YOLO 时classes.txt顺序和data.yaml的names不一致,模型学的是错位标签。另一个原因是 TXT 里坐标没归一化,还是绝对像素值,YOLO 解析时当成 0 到 1 的数,框全跑到图外。

解决:先跑一遍校验脚本,确认 TXT 每行第二个值在 0 到 1 之间。再核对classes.txt和data.yaml的names逐行一致。两个都对了还不行,用yolo detect train加--verbose看数据加载日志,确认标签被正确读取。

4.2 现象:验证集 mAP 高但测试集一塌糊涂

原因:370 张切分时如果按文件名顺序切,可能训练集和验证集来自同一批拍摄场景,测试集却是另一个场景,分布不一致。鹅的拍摄角度、光照、背景差异大,随机切分容易造成这种“假高分”。

解决:切分前先按场景分组,同一场景的图要么全在训练集要么全在测试集。如果场景标签没有,用图片的 EXIF 时间或文件名前缀粗分。测试集 mAP 比验证集低 0.15 以内算正常,低太多就是分布问题。

4.3 现象:模型把鹅和背景里的白色物体混淆

原因:370 张里如果鹅的白色羽毛和背景白色墙面、水面反光同时出现,模型学到的特征不够判别。小数据下模型容易走捷径,学颜色而不是形状。

解决:增强里加大 HSV 抖动的幅度,特别是hsv_v和hsv_s,让模型对颜色不敏感。另外检查标注,把明显不是鹅的误标框删掉。如果背景单一,考虑加一些负样本图(没有鹅的图),YOLO 支持空标注文件,能降低误检。

4.4 现象:训练到一半 loss 突然变 NaN

原因:小数据配大学习率容易梯度爆炸,尤其是 batch 里有异常样本时。另一个原因是标注框宽高为 0,归一化后除零。

解决:把lr0降到 0.001 再试,加warmup_epochs=3让学习率慢慢升。检查 TXT 里有没有w=0或h=0的行,有就删掉或修正。YOLOv8 默认有梯度裁剪,但小数据下还是保守点好。

4.5 现象:推理时框重叠严重,同一只鹅出多个框

原因:NMS 的iou阈值设太高,或者训练时正样本分配太宽松。370 张下模型对鹅的边界学得不够准,框会偏大。

解决:推理时把conf提到 0.4 以上,iou降到 0.5。训练时如果用了mosaic增强,最后 10 个 epoch 关掉,让模型在真实分布上收一收。YOLOv8 的close_mosaic参数设成 10 就行。

5. 把 370 张用到极致:半自动标注与增量迭代

370 张训出第一版模型后,别停在这。真正让这个小数据集发挥价值的做法是拿模型去标新图,人工修正后加入训练集,滚雪球式迭代。具体操作:用训好的best.pt对未标注的鹅图跑推理,导出 YOLO 格式的预测 TXT,然后用标注工具(LabelImg 或 AnyLabeling)打开图片和预测框,人工只做删改,不做从零画框。这一步能把单张标注时间从 2 分钟压到 20 秒。

yolo detect predict \ model=runs/goose/exp1/weights/best.pt \ source=new_images/ \ conf=0.3 \ save_txt=True \ save_conf=True \ project=auto_label \ name=round1

save_txt=True会在auto_label/round1/labels下生成 YOLO 格式 TXT,conf=0.3放低阈值多召回一些框,人工删比人工画快。修正后的 TXT 直接放进训练集,重新跑训练时把epochs降到 50,学习率降到 0.001,做微调而不是重训。

增量迭代的节奏我一般这样控:第一轮 370 张训基线,第二轮加 100 到 200 张修正图,第三轮再加 200 张,到 800 张左右 mAP 通常能比基线涨 0.1 到 0.15。超过 1000 张后收益递减,这时候该考虑的是换更大的模型或加更多类别,而不是继续堆图。验证方法很简单:每轮留一个固定的测试集不参与训练,只看测试集 mAP,涨了就继续,平了就停。

我自己的习惯是每轮迭代都存一份data.yaml和classes.txt的快照,标注格式这东西,改着改着就忘了当初的顺序,留个后悔药比事后排查省事得多。鹅检测这个方向,370 张起步完全能跑通,关键是别在格式转换和切分上翻车,把省下的时间花在迭代上。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 20:33:50

Java Web教材征订系统源码拆解:从MVC闭环到并发库存实战

简介&#xff1a;这份高校教材征订管理系统源码包面向计算机专业学生与Java初学者&#xff0c;对应大学生课程设计场景&#xff0c;用于解决教材信息维护、学生选课订购、教师需求提交与订单统计等业务问题&#xff0c;可作为课程设计参考或Java Web入门练手项目。压缩包共603个…

作者头像 李华
网站建设 2026/10/1 20:33:30

树莓派5工业部署六项硬性适配要点

1. 项目概述&#xff1a;树莓派5进车间&#xff0c;不是插上电就能跑的“即插即用”设备“树莓派5进车间”这七个字&#xff0c;听上去像一句轻描淡写的操作指令&#xff0c;实则是一道横在工业现场与消费级单板机之间的硬门槛。我去年接手一个产线视觉质检升级项目&#xff0c…

作者头像 李华
网站建设 2026/10/1 20:32:35

基于大模型人工智能的芯片设计时序分析系统平台软件

基于大模型人工智能的芯片设计时序分析系统平台软件基于大模型人工智能的芯片设计时序分析系统面向3nm及以下先进制程&#xff0c;融合时序垂类大模型、智能体协同与传统静态时序分析引擎&#xff0c;构建新一代芯片时序分析核心系统&#xff0c;可实现时序收敛效率跃升&#x…

作者头像 李华
网站建设 2026/10/1 20:31:34

ODrive+FreeRTOS:电机控制从能转到稳转的实时架构升级

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华