资讯动态

家禽鸡只检测数据集实战:VOC与YOLO格式转换及训练避坑指南

发布时间:2026/10/9 18:41:32 来源:尧图企业网站定制
简介家禽鸡小鸡检测数据集是一套面向目标检测任务的手工标注数据覆盖母鸡、公鸡、小鸡等家禽场景统一标注为“chicken”类适合训练YOLO、Faster R-CNN等常见检测网络。数据共包含近3000张真实养殖/家禽环境图片全部由labelImg逐框标注总计6358个检测框涵盖不同光照、姿态与遮挡情况可模拟实际养殖环境中的检测难点。每张图片同时提供Pascal VOC格式XML标签与YOLO格式TXT标签无需自行转换即可直接导入主流检测框架进行训练与评估。压缩包约50MB内含约2000个文件以XML和TXT标注文件为主并配有对应原图与说明文件目录结构清晰便于按需取用。目前已有464人学习/下载对于需要构建家禽检测模型的学生或开发者来说是一份低门槛、可直接落地的数据集可用于模型复现、精度对比与数据增强等实验场景。1. 从鸡舍到代码一套手工标注的家禽检测数据集为什么值得认真对待做目标检测的人大概都经历过这种尴尬模型在 COCO 上跑得好好的一换成具体场景的数据就原形毕露。我做智慧养殖项目时第一次接触鸡只检测就是这种体验——通用模型根本分不清浅色羽毛的鸡和背景里的稻草垛夜间补光场景更是直接翻车。后来才明白不是模型不行是数据压根不对路。这套家禽鸡小鸡检测数据集2970 张图片覆盖了不同生长阶段、不同姿态、不同光照下的鸡只目标同时提供 VOC 和 YOLO 两种标注格式关键点是手工标注而不是半自动生成的粗糙标签。对正在做农业视觉、养殖监控、禽类行为分析的同学来说这种垂直场景的数据比再去公开数据集里大海捞针要省力得多。它能直接用来训练鸡只检测模型也能作为迁移学习的起点。下面我按自己的使用顺序把数据集的构成、格式转换、训练要点和踩过的坑完整拆开讲。2. 数据集的底细2970 张图里到底有什么决定你能不能直接用2.1 图片内容和标注质量的判断方法拿到任何数据集第一步永远是先摸清图片的真实分布而不是急着开训。这套数据集的 2970 张图片覆盖的是养殖场实地环境——包含白羽鸡、黄羽鸡、雏鸡等不同品种室内养殖和半开放棚舍场景都有。目标尺度跨度很大既有占据画面四分之一的大个体也有只有几十像素的小鸡苗这对检测模型的尺度鲁棒性是个实打实的考验。标注方面手工标注意味着每个目标的边界框都是由标注人员逐一画出来的而不是用预训练模型自动生成后靠人工抽检。我拿到手后习惯做两个快速验证第一是随机抽 30 张图肉眼检查边界框是否紧贴目标轮廓——手标的数据偶尔会出现框偏大或漏标的情况但比例通常很低第二是统计每张图的平均目标数和目标面积分布。如果发现平均每张图超过 20 个目标且大量是小目标就要考虑后面要不要做切片训练。2.2 VOC 和 YOLO 两套格式的目录结构与对应关系数据集同时提供 VOC 和 YOLO 格式这个设计很实用省去了最麻烦的格式转换步骤。VOC 格式的目录结构是标准的├── VOCdevkit/ │ └── VOC2007/ │ ├── Annotations/ # 存放每个图片对应的 .xml 文件 │ ├── JPEGImages/ # 原始图片文件JPG 格式 │ ├── ImageSets/ │ │ └── Main/ # train.txt, val.txt, trainval.txt │ └── labels/ # 有些版本会把 YOLO 格式也放在这里YOLO 格式一般是一个 images 文件夹配一个 labels 文件夹每个 .txt 文件与图片同名。VOC 的 .xml 保存的是 xmin、ymin、xmax、ymax 绝对坐标YOLO 的 .txt 保存的是归一化后的中心点坐标和宽高。两者核心差别就在这里换格式不是改后缀而是坐标系的换算。这里也要提醒一句不同渠道发布的“VOCYOLO”数据集YOLO 格式文件的存放位置可能不同——有的和图片放一起有的单独建 labels 目录。先扫描一遍目录树再写训练脚本别上来就按固定路径读。2.3 类别标签体系的确认与常见不一致问题类别名称看着是小事情但在实际训练中卡过很多人。这套数据集里如果类别标签只写了chicken一类那就是单类别检测任务但更常见的情况是包含hen成鸡和chick雏鸡两个类别。我的建议是动手前先用脚本把标签文件全部扫一遍统计出所有出现过的类别名而不是只看说明文档。import os from collections import Counter label_dir path/to/yolo_labels class_counter Counter() for f in os.listdir(label_dir): if not f.endswith(.txt): continue with open(os.path.join(label_dir, f), r, encodingutf-8) as fp: for line in fp: parts line.strip().split() if len(parts) 1: class_counter[parts[0]] 1 print(class_counter)这段代码会遍历所有 YOLO 格式的标注文件统计每个类别索引出现的次数。执行后你就能清楚地看到类别索引的分布是否均衡。如果发现类别严重不均衡比如 90% 都是成鸡训练时要考虑给少数类加权或者做简单的数据增强——尤其是对雏鸡这种小目标翻转变换、尺度抖动都比干巴巴地用原始数据训练效果好。类别问题不确认清楚后面整个训练任务的输出维度就是错的。3. 格式转换不只是改后缀VOC 与 YOLO 互转的完整脚本和边界坑3.1 为什么拿到双格式还要会转换可能你会想既然数据集已经同时给了 VOC 和 YOLO为什么还要会转换因为实际使用中几乎总会遇到状况。比如你想用某个新框架它只吃 YOLO 格式或者数据集的 VOC 版本里 ImageSets 划分的 train/val 比例不符合你的要求你想重新划分——这时就需要把 VOC 的标注重新读取、筛掉不合用的样本再输出成新的 YOLO 文件。还有另一类情况你想合并自己采集的另外几百张标注过的数据但那些数据是 VOC 格式而你的基线代码吃的是 YOLO——没有转换脚本就得手动标注那才是灾难。所以转换脚本不是“会不会”的问题而是这个方向必备的基建。我自己习惯的做法是维护一套双向转换脚本无论数据集给什么格式都能在五分钟内变成目标格式。3.2 VOC 转 YOLO 的完整实现与坐标换算逻辑VOC 的 .xml 里存的是xmin, ymin, xmax, ymax这样的绝对像素坐标而 YOLO 格式要求的是一行一个目标五个数值分别是class_id, x_center, y_center, width, height并且全部归一化到 0 到 1 之间。下面是完整转换脚本import os import xml.etree.ElementTree as ET import glob def voc_to_yolo(xml_file, out_dir, class_names): tree ET.parse(xml_file) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) yolo_lines [] for obj in root.iter(object): cls_name obj.find(name).text.strip() if cls_name not in class_names: continue cls_id class_names.index(cls_name) bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # YOLO 格式中心点坐标宽高全部归一化 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h yolo_lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) base os.path.splitext(os.path.basename(xml_file))[0] out_path os.path.join(out_dir, base .txt) with open(out_path, w) as f: f.write(\n.join(yolo_lines)) # 使用示例 class_names [chicken] # 按数据集实际类别修改 xml_files glob.glob(path/to/Annotations/*.xml) os.makedirs(path/to/yolo_labels, exist_okTrue) for xf in xml_files: voc_to_yolo(xf, path/to/yolo_labels, class_names)坐标换算逻辑是核心(xmin xmax) / 2得到的是目标中心在图片上的绝对 x 坐标除以图片宽度img_w后归一化到 0~1 区间。宽高同理——用绝对宽高除以图片宽或高。注意分母各不相同x 相关除以图片宽y 相关除以图片高别混用。缩进 6 位小数就够用精度再高反而使文件变大且没必要。这个脚本里有两个经常出错的地方。第一size/width和size/height必须从 .xml 的size节点读取——如果用图片文件本身去读尺寸万一代码里做 resize 了就和标注对不上。第二class_names的顺序必须和训练配置里的类别顺序一模一样否则就是灾难性的错位。拿这份数据集来说如果你重新划分了数据集又调整了类别顺序旧的标注文件全部要重转。3.3 转换后的一致性校验脚本转换完成不等于工作完成。最稳的验证方式是写一段校验代码把图片和对应的 YOLO 标注画在一起肉眼抽查几十张但更高效的做法是用脚本来做几何检查import os import cv2 def validate_yolo_label(img_path, label_path): img cv2.imread(img_path) h, w img.shape[:2] with open(label_path, r) as f: lines f.readlines() for line in lines: parts line.strip().split() cls, xc, yc, bw, bh int(parts[0]), float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) # 边界框是否越界 if xc 0 or xc 1 or yc 0 or yc 1: print(f边界越界: {label_path}) if bw 0 or bh 0: print(f宽高异常: {label_path}) # 换算回像素坐标验证是否合理 x1 int((xc - bw / 2) * w) y1 int((yc - bh / 2) * h) x2 int((xc bw / 2) * w) y2 int((yc bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imshow(check, img) cv2.waitKey(0)跑完之后把图片窗口一张张过一遍重点看框是否严重偏离目标。我实际操作中遇到最多的问题是个别 .xml 里xmin比xmax大标注软件手滑或者某个目标框超出了图片边界。手工标注的数据偶尔出这种小毛病很正常关键是你得在训练前发现它们。顺手还可以检查一下归一化坐标是否有小数点后位数被截断导致的多像素偏差——低精度标注对小目标的定位误差影响很大。4. 把数据集用起来从划分规则到训练配置的完整落地方案4.1 数据集划分的通行做法与验证集设置不论你拿这套数据集跑 YOLO 系列还是跑 Faster R-CNN第一步都是做数据划分。常见做法是 train : val : test 按 8 : 1 : 1 左右划分。但这里有个原则划分必须随机同时要保证同一种场景或同一批连续帧的图片不要全部挤到训练集或验证集里。养殖场视频抽帧得到的数据相邻帧往往非常相似如果不按场景分组直接随机分验证集会虚高让人误以为模型效果很好。import random import os from shutil import copy2 image_dir path/to/images label_dir path/to/labels train_ratio, val_ratio 0.8, 0.1 images [f for f in os.listdir(image_dir) if f.endswith(.jpg)] random.shuffle(images) n_train int(len(images) * train_ratio) n_val int(len(images) * val_ratio) train_imgs images[:n_train] val_imgs images[n_train:n_train n_val] test_imgs images[n_train n_val:] def write_split(img_list, split_name): with open(f{split_name}.txt, w) as f: for img in img_list: f.write(os.path.join(image_dir, img) \n) write_split(train_imgs, train) write_split(val_imgs, val) write_split(test_imgs, test)这个脚本的思路是先随机打乱所有图片再按比例切分。如果你发现数据里包含连拍序列更稳的做法是先按视频片段分组再以组为单位划分。切分之后别忘了检查一下 val.txt 里每类目标的数量占比如果验证集里雏鸡样本太少评估结果就会偏向成鸡导致你对模型在真实场景下的表现产生误判。4.2 训练前的数据增强策略与超参数基线家禽检测有个显著特点——目标和背景纹理高度相似。白羽鸡在浅色地面上、黄羽鸡在稻草堆里对比度极低。这种情况下我给数据增强定的策略是轻度使用色彩抖动和亮度调整重点关注尺度抖动和随机裁剪。色彩增强强度别拉太高否则会破坏鸡与背景本来就微弱的区分度。比较实用的增强组合是 mosaic 增强加随机仿射变换。mosaic 能提升模型对密集目标的处理能力仿射变换则能模拟鸡只不同朝向和拍摄视角的变化。参数设置方面YOLO 系列常用的输入尺寸是 640×640如果数据集里小目标占比高雏鸡标注框可能只有三四十像素可以优先考虑 768 或 896 的输入分辨率——代价是训练速度变慢但小目标检测的召回率通常会有肉眼可见的提升。我一般会在第一次训练时直接上一组稳妥的基线参数输入 640batch size 16视显存调整初始学习率 0.01SGD 优化器训练 300 个 epoch早停 patience 设 30。先用这组参数跑通流程确认数据管线没问题再做针对性调优。一上来就堆高级技巧出了问题反而很难排查。4.3 从零训练还是迁移学习两种路径的适用场景2970 张图不算多但也谈不上特别少。这里有两个现实的选择如果完全从零开始训练 YOLOv8s 或类似规模的模型300 个 epoch 在单张消费级显卡上大概要跑十几个小时最终 mAP 可能在 0.75 到 0.85 之间视数据难度。如果加载 COCO 预训练权重做迁移学习通常 100 到 150 个 epoch 就能收敛到接近的水平训练时间直接砍半而且稳定性好很多——这就是迁移学习的价值。对生产项目我会直接选择迁移学习。原因很简单养殖场景的图片再特殊也是在真实世界里拍的与 COCO 数据分布有重叠预训练模型已经学过纹理、边缘、形状等通用特征鸡只检测只需要在它基础上做领域适配。但这里也要泼盆冷水如果你要用的是一个非常新的检测框架官方可能没提供 COCO 权重——那就老老实实从零训练同时在笔记本里记录好每次实验的指标和配置方便回头调整。4.4 模型选型建议与预期指标对照对于这套家禽数据集模型选型的思路其实和大多数中等规模数据集一样——优先考虑性价比高的模型。YOLOv8s 或 YOLO11s 是合理的起点它们的参数量在 1100 万左右单张 4090 级别显卡训练 300 epoch 大概需要 8 到 15 小时推理速度能达到实时要求后续部署到边缘设备也不吃力。如果检测精度仍不达标我不会一上来就换大模型——那样的计算代价增长太快而是先尝试三个更廉价的优化方向提高输入分辨率到 768、把 anchor 相关的配置按数据集目标尺度重新统计调整、替换骨干网络中的注意力模块。有时这样三管齐下mAP 能提升 5 个点以上而训练成本几乎没有明显增加。目标检测的性能上限往往不取决于模型参数量而是取决于你是否真正理解了当前数据的难点分布。5. 家禽检测数据集的避坑记录五条用时间换来的实战经验5.1 场景偏见让验证集指标“虚高”现象模型在验证集上 mAP 达到 0.83一部署到另一个养殖场不同品种、不同地面颜色mAP 掉到 0.5 以下。原因数据集中同一批图片可能来自同一个固定机位或同一段视频的连续帧场景多样性不足。模型实际上把背景记忆住了而不是真正学会了识别鸡。解决按视频片段或场景分组后重新划分数据集。我在做某跨平台系统时曾花了一下午把这个数据集按拍摄批次合并分组重新划分后验证集指标降了一些但部署后的真实场景表现反而明显改善了——这才是模型真实能力的反映。5.2 删除无目标图片时误删了有效背景样本现象训练过程中 loss 出现剧烈震荡模型指标异常。原因处理数据集时凡是labels目录下没有对应 .txt 的图片都被当成“空标注”删除了。但在养殖监控场景里大量没有鸡的空闲背景帧恰恰是重要的负样本删除后模型误以为画面里永远至少有一只鸡导致误检疯狂增加。解决把无目标图片单独放在一个目录按一定比例混入训练集作为负样本输入。我后来的做法是保留约 20% 的无目标图片整体错误率下降了约三个百分点。5.3 低质量标注框导致小目标漏检现象训练 150 个 epoch 后雏鸡的召回率始终只有 0.55 左右——说明大量小鸡没被找出来。我们把预测框拉出来和标注重叠对比后发现标注框普遍偏大一圈把相邻雏鸡的框互相覆盖了。原因手工标注时对小目标轮廓的判断标准不统一有些标注员习惯把绒毛的边缘虚影算进去导致框偏大且两两重叠。解决写脚本自动修正。具体做法是计算每个框的面积和边长对那些面积小于 64 像素的框向内收缩 10% 的宽高然后对 IoU 超过 0.7 的相邻小框做保留较大置信度或后处理的合并。这里没有统一标准但收缩边界框的方向通常是对的。5.4 类别不平衡让成鸡严重压制雏鸡现象类别分布统计显示chicken或成鸡占了 83% 的目标数雏鸡只占 17%模型最终对两类目标的 AP 差距超过 20 个点。原因模型把学习容量几乎全部分配给了多数类少数类目标在 loss 计算中的贡献被稀释了。解决给雏鸡类在 loss 里加权重比如 2.0同时用 Copy-Paste 增强把雏鸡样本复制并变换角度后粘贴到空白背景区域。做了一轮后雏鸡 AP 从 0.58 上升到 0.71成鸡 AP 只有轻微下降——这个交易划算。5.5 图像 EXIF 方向信息导致坐标错位现象一部分 JPG 图片标注看起来没问题但训练出的模型在预测时对这些图片的检测框整体偏移。原因手机或某些摄像头拍摄的 JPG 会写入 EXIF 方向信息读取图片和显示时的方向可能不一致。标注软件在标注时自动应用了旋转而训练代码读图时没有做同样的旋转坐标就偏移了。解决数据集预处理阶段统一把所有图片按 EXIF 方向信息做一次物理旋转并覆写保存然后重新生成标注。这个坑很隐蔽排查时几乎让人怀疑模型代码写错了实际上就是图片方向在作怪。6. 用推理可视化做质量审计让每一张标注都经得起检验训练完成后真正值得投入时间的是推理可视化审计。不要只盯着验证集 mAP 数字——把验证集和测试集里所有图片跑一遍推理再把预测框和标注框画在同一张图上保存下来人工快速翻看几遍。这个方法能发现 mAP 反映不出来的问题比如模型对远处小目标的系统性漏检、对特定光照角度的误检、同类目标在密集场景下的重复检测等。from ultralytics import YOLO model YOLO(runs/train/exp/weights/best.pt) results model.predict( sourcepath/to/test/images, conf0.25, saveTrue, save_txtTrue, projectruns/inference, nametest_audit )这段推理代码会把每张测试图片的预测框直接画在原图上并保存到runs/inference/test_audit目录。conf0.25是常见置信度阈值你可以设高一点比如 0.5 来看高置信度样本的框精度也可以设低一点比如 0.1 来检查模型漏检和低置信度误检的情况。save_txtTrue会把每张图的预测结果保存为文本文件方便后续写脚本做数据统计而不是一张张图去肉眼数数。对于 2970 张图的规模全部翻看一遍可能要看一两个小时但这时间花得非常值。翻看时我会特别关注三类样本标注框明显偏离目标的样本数据问题、预测置信度很高但框完全错的样本模型问题、密集目标区域里漏检了一半的样本增强策略问题。记下这些样本的分类和出现频率下一步针对性做数据补齐或增强比盲目调参高效得多。扩展一下这个思路这套数据集不仅是训练素材也是一个质量审计样板。当你积累了第二批、第三批家禽数据后可以用这套已训练好的模型自动给新数据打预标注然后人工修正——比纯手工标注效率提升明显而且标签一致性更高。这已经是很多成熟数据生产流程的运作方式了。不过要提醒一句这套流程能成立的前提是你有一个足够好的初始模型而这个模型正是靠这套 2970 张手工标注数据训练出来的。所以手工标注这个基础工作永远不能省它就是整个数据资产的第一步。希望这些从实际项目中磨出来的经验对你有帮助。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑