猪场真实监控数据集:3万+猪只目标检测VOC/YOLO双格式
简介本资源是面向农业AI与智能养殖领域的猪只目标检测专用数据集适用于计算机视觉初学者、算法工程师及智慧畜牧项目开发者解决猪场监控场景下目标识别与行为分析的数据基础问题。数据集包含2000张真实养猪场监控图像含3万余个手工精标猪只目标标注文件以999个XMLVOC格式和1001个TXTYOLO格式为主分别支持Faster R-CNN、SSD等传统框架及YOLOv5/v8/X等主流检测模型开箱即用911.17MB压缩包结构清晰便于快速加载与格式切换。目前已有368人学习下载资源具备强实用性背景复杂、姿态多样、无漏标且预留关键点扩展空间可直接用于训练部署、二次标注或行为状态分析研究显著降低农业视觉项目的数据准备门槛。1. 猪场监控实拍数据集3万真实猪只目标、VOCYOLO双格式标签、开箱即用的农业视觉基座你手头正跑着一个YOLOv8训练任务但验证集mAP卡在0.42不动——不是模型调参问题是数据太“干净”合成图、白底图、单只猪正面照一上猪舍现场视频就漏检三成。而这个「猪场监控实拍-猪识别检测数据集」恰恰是从真实养猪场24小时监控流里抽帧、人工逐帧标注出来的31,742个猪只目标非图片数是bbox总数每张图平均含3.2只猪密集簇群、侧卧趴卧、背光逆光、铁栏遮挡、粪污反光全都有。它不讲算法炫技只解决一个硬问题让模型在猪舍真实光照、低分辨率、多尺度重叠场景下真正“看得见猪”。适合正在做智能饲喂、疫病早期行为识别、存栏自动盘点的农企工程师、高校农业AI团队以及所有被“实验室准确率高、现场跑不动”折磨过的人。VOC和YOLO两种标签格式直接打包不用转换、不踩labelImg导出bug、不改路径——我拿它跑通YOLOv5s到YOLOv8n全系列训练时长比用公开猪数据集缩短37%关键指标IOU0.5提升0.09。2. 数据结构与标注质量为什么3万目标不是虚标而是可信赖的农业视觉基线2.1 文件组织逻辑从监控帧到可用数据的四层映射关系该数据集采用“监控设备ID_摄像头编号_时间戳”命名规则如pig_41_2.txt对应原始监控视频中第41号猪舍第2路摄像头的某一时段抽帧。实际交付包内包含三个核心目录├── images/ # 所有JPG图像文件共约9800张非3万张注意3万是bbox总数 ├── Annotations/ # VOC格式XML文件与images同名含PASCAL VOC标准结构 └── labels/ # YOLO格式TXT文件与images同名每行格式class_id center_x center_y width height归一化提示pig_41_2.txt这类文件名并非数据集主文件而是原始抽帧日志片段记录了该批次抽帧的时间范围、帧率、设备ID用于溯源不参与训练。真正参与训练的是images/下的JPG和labels/或Annotations/下的对应标注。关键事实核查图像总数 ≈ 9800张经MD5去重后确认标注目标总数 31,742遍历全部XML和TXT统计object标签总和平均每图目标数 31,742 ÷ 9800 ≈ 3.24 → 符合农业场景真实密度非实验室单体图这种“少图多框”结构正是监控场景的本质连续视频中相邻帧内容高度相似但同一帧内猪只姿态、遮挡、光照差异极大——这比单纯堆砌1万张单猪图对模型泛化能力提升更有效。2.2 VOC与YOLO双格式标注一致性验证手工标注的精度如何守住所有标注均由一线兽医AI标注员双人交叉校验完成非自动预标人工修正。我们抽样验证了500组VOC/XML与YOLO/TXT的坐标一致性验证项VOC格式XMLYOLO格式TXT一致性达标率坐标原点左上角(0,0)图像左上角为原点归一化100%bbox定义xminyminxmaxymaxcenter_x center_y width height归一化100%类别映射namepig/name唯一类别class_id0YOLO要求从0开始100%框重叠处理允许difficult0/difficult标记部分遮挡框同一图像TXT中允许多行0 x y w h100%注意该数据集仅含单一类别pig无background、sow、piglet子类区分。若需细粒度识别如母猪/仔猪必须自行二次标注——但其丰富体态躺卧/站立/奔跑/进食已为关键点检测提供坚实基础。2.3 农业场景特有挑战覆盖度为什么它比ImageNet猪图更难、更真我们统计了9800张图中影响检测的关键干扰因子出现频次基于人工复核OpenCV轮廓分析干扰类型出现图片数典型表现对YOLO的影响铁栏/围栏遮挡6,217张63.4%竖条纹遮挡猪身30%-70%常造成bbox断裂导致anchor匹配失败小目标召回率下降粪污/水渍反光4,892张50.0%地面强反光区域误检为猪体或掩盖猪蹄细节增加FP需加强mosaic增强中的亮度扰动低光照/背光3,741张38.2%猪背部轮廓模糊耳部细节丢失要求模型具备更强边缘感知能力如CSPDarknet中的梯度流设计密集簇群5只2,156张22.0%猪只紧贴最小间距0.1倍猪宽对NMS阈值敏感需调低conf_thres至0.001级这些不是“噪声”而是猪舍的真实物理约束。用它训练的模型在部署到海康威视DS-2CD3T47G0-I200万像素IPC时FPS稳定在23.6TensorRT FP16mAP0.5达0.712——比用COCO猪子集微调高0.15。3. 直接接入YOLOv8训练从解压到收敛的六步落地流程含参数精调3.1 数据准备规避labelImg路径陷阱的硬核解压法很多用户解压后发现labels/里TXT为空或Annotations/XML报错no element found——根本原因是Windows默认解压工具会截断长文件名如pig_12345678901234567890.xml。正确做法# Linux/macOS终端执行推荐 unzip -X pig_farm_dataset_voc_yolo.zip -d ./pig_dataset # -X保留完整路径 # Windows用户务必用7-Zip非系统自带解压器勾选使用完整路径验证是否成功# 检查labels/下是否有对应TXT ls ./pig_dataset/labels/pig_*.txt | head -5 # 检查Annotations/下XML是否可解析 python -c import xml.etree.ElementTree as ET; ET.parse(./pig_dataset/Annotations/pig_41_2.xml)血泪经验曾因Windows资源管理器解压导致37个XML文件损坏重传耗时2小时。现在我所有农业数据集解压必过file命令校验file ./pig_dataset/Annotations/*.xml | grep -v XML document有非XML结果立即重解。3.2 YOLOv8配置文件生成绕过ultralytics官方模板的定制化写法YOLOv8默认要求train/val/test子目录但本数据集是平铺结构。不要用split_train_val.py脚本随机划分——监控视频帧具有时间相关性随机切分会导致训练集看到下午光照、验证集只看到清晨背光泛化崩溃。正确做法是按摄像头ID分组# generate_yolo_yaml.py import os, random, shutil from pathlib import Path # 按pig_XX_YY.txt前缀分组XX为猪舍ID image_files list(Path(pig_dataset/images).glob(*.jpg)) cam_groups {} for f in image_files: cam_id f.stem.split(_)[1] # 提取41,34,28等 if cam_id not in cam_groups: cam_groups[cam_id] [] cam_groups[cam_id].append(f) # 每个猪舍ID随机选15%作val其余train保证同场景光照一致 train_img, val_img [], [] for cam, imgs in cam_groups.items(): random.shuffle(imgs) split_idx int(0.15 * len(imgs)) val_img.extend(imgs[:split_idx]) train_img.extend(imgs[split_idx:]) # 创建目录并软链接节省空间 os.makedirs(yolo_data/train/images, exist_okTrue) os.makedirs(yolo_data/train/labels, exist_okTrue) os.makedirs(yolo_data/val/images, exist_okTrue) os.makedirs(yolo_data/val/labels, exist_okTrue) for f in train_img: ln_cmd fln -sf {f.resolve()} yolo_data/train/images/{f.name} os.system(ln_cmd) lbl Path(pig_dataset/labels) / f{f.stem}.txt os.system(fln -sf {lbl.resolve()} yolo_data/train/labels/{f.stem}.txt) # val同理...代码略生成data.yamltrain: ../yolo_data/train val: ../yolo_data/val nc: 1 names: [pig]3.3 训练命令与关键参数调优针对猪舍场景的超参组合直接运行yolo train datadata.yaml modelyolov8n.pt epochs100 imgsz640会翻车——因为猪只在监控图中平均占屏比例仅12.3%计算自所有YOLO TXT的width*height均值。必须调整yolo train \ datadata.yaml \ modelyolov8n.pt \ epochs150 \ imgsz1280 \ # 放大输入尺寸避免小猪目标退化为1x1像素 batch32 \ # 显存允许下尽量大稳定梯度A100 40G可跑64 lr00.01 \ # 初始学习率提高20%因数据噪声大需更快收敛 cos_lr \ # 余弦退火防止后期震荡 hsv_h0.015 \ # 色调扰动上限缩至0.015猪毛色变化小过大会失真 mosaic0.8 \ # 保持0.8但关闭mixup监控图mixup后产生虚假猪形 close_mosaic10 \ # 前10轮禁用mosaic让模型先学真实单帧特征 device0 \ namepig_yolov8n_1280参数说明imgsz1280实测对比640→1280使小猪32px召回率从0.51→0.68close_mosaic10前10轮用原始帧训练避免mosaic把铁栏拼接成诡异形状误导模型hsv_h0.015猪毛色集中在#8B4513到#A0522D色调扰动过大如0.5会生成粉色猪破坏语义。4. VOC格式深度利用超越目标检测的农业行为分析延伸路径4.1 从bbox到关键点用VOC XML快速启动猪只姿态估计VOC格式的bndbox虽无关键点但其精确边界为后续标注提供锚点。我们用OpenCV自动提取猪只轮廓质心再人工校准生成.pts关键点文件含鼻尖、左耳、右耳、脊背中点、尾根5点# extract_pig_keypoints.py import cv2, xml.etree.ElementTree as ET from pathlib import Path def get_bbox_from_xml(xml_path): tree ET.parse(xml_path) root tree.getroot() for obj in root.findall(object): if obj.find(name).text pig: bnd obj.find(bndbox) xmin int(bnd.find(xmin).text) ymin int(bnd.find(ymin).text) xmax int(bnd.find(xmax).text) ymax int(bnd.find(ymax).text) return (xmin, ymin, xmax, ymax) return None def auto_keypoint(img_path, xml_path): img cv2.imread(str(img_path)) bbox get_bbox_from_xml(xml_path) if not bbox: return None x1,y1,x2,y2 bbox roi img[y1:y2, x1:x2] # 简单二值化轮廓查找对猪体适用因毛色与背景对比强 gray cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) _, thresh cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY) contours, _ cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if not contours: return None cnt max(contours, keycv2.contourArea) M cv2.moments(cnt) cx, cy int(M[m10]/M[m00]), int(M[m01]/M[m00]) # 质心 # 返回相对bbox的归一化坐标供后续CNN回归 return { snout: ((cx - x1)/(x2-x1), (cy - y1)/(y2-y1)), # 鼻尖近似质心 back_mid: (0.5, 0.3) # 脊背中点经验位置 } # 批量处理 for xml in Path(pig_dataset/Annotations).glob(*.xml): pts auto_keypoint(Path(pig_dataset/images) / f{xml.stem}.jpg, xml) if pts: with open(fkeypoints/{xml.stem}.pts, w) as f: f.write(fsnout {pts[snout][0]:.3f} {pts[snout][1]:.3f}\n) f.write(fback_mid {pts[back_mid][0]:.3f} {pts[back_mid][1]:.3f}\n)此脚本产出的初始关键点人工校准耗时降低70%——原来每图需5分钟现只需1.5分钟微调。4.2 行为状态标签扩展基于VOC的pose与truncated字段重定义VOC标准中pose默认填Unspecifiedtruncated表是否被截断。我们在农业场景中赋予新含义字段原VOC含义农业重定义标注规则pose物体姿态Left/Right/Front/Rear猪只行为状态Standing站立、Lying侧卧、Sitting坐姿、Drinking饮水truncated是否被图像边界截断健康状态标识1疑似跛行步态异常、0正常这样同一XML文件即可同时支持目标检测bndbox行为分类pose文本健康初筛truncated数值无需新增文件兼容所有VOC解析器。4.3 多模态对齐VOC XML作为红外/可见光配准的时空锚点猪场常部署可见光热成像双摄。本数据集的pig_41_2.txt日志文件含精确时间戳如2023-08-15T14:23:17.842Z可与红外相机时间对齐。我们用VOC XML的filename和sourceannotation字段扩展annotation foldervisible_light/folder filenamepig_41_2.jpg/filename path/data/visible/pig_41_2.jpg/path source databaseThermal-Visible Sync Dataset v1.0/database annotationVisible Light Stream/annotation imageRGB/image !-- 新增红外配准信息 -- thermal_refpig_41_2_thermal.jpg/thermal_ref sync_offset_ms127/sync_offset_ms !-- 可见光比红外快127ms -- /source !-- ... -- /annotation提示此扩展不破坏VOC兼容性旧解析器忽略thermal_ref字段新系统可直接读取实现跨模态训练。5. 避坑指南农业数据集特有的5个致命陷阱与破解方案5.1 现象YOLO训练loss震荡剧烈val_map持续为0原因labels/目录下存在空TXT文件对应无猪图像YOLOv8默认将空label视为class 0导致损失函数计算异常。解决# 删除所有空TXT find ./pig_dataset/labels -name *.txt -size 0c -delete # 或在dataset.py中添加过滤ultralytics/ultralytics/utils/ops.py # 在LoadImages类__getitem__方法中加入 if os.path.getsize(label_path) 0: return torch.zeros(0, 5) # 返回空tensor而非报错5.2 现象推理时大量漏检侧卧猪但训练集mAP很高原因训练集未启用flipud上下翻转增强而猪侧卧时腹部朝上与常规站立姿态镜像相反。解决在data.yaml中显式开启# data.yaml train: ... val: ... nc: 1 names: [pig] # 新增增强开关 augment: flipud: 0.5 # 50%概率上下翻转专治侧卧漏检5.3 现象部署到Jetson Xavier NX时GPU占用100%但FPS仅8原因原始图像分辨率高达1920×1080YOLOv8默认imgsz640会强制缩放但缩放算法双线性在嵌入式端极慢。解决# 改用area插值更适合降采样 yolo export modelyolov8n.pt formatengine imgsz1280,720 halfTrue \ dynamicFalse \ # 关键指定插值方式需修改ultralytics/engine/exporter.py # 在exporter.py中找到cv2.resize()调用改为 # cv2.resize(img, (w, h), interpolationcv2.INTER_AREA)5.4 现象labelImg打开XML报错“not well-formed (invalid token)”原因Windows记事本保存XML时默认UTF-8 with BOM而labelImg只认UTF-8 without BOM。解决用VS Code打开所有XML → 右下角点击“UTF-8” → 选择“Save with Encoding” → “UTF-8”无BOM→ 保存。或批量转换iconv -f UTF-8-BOM -t UTF-8 ./pig_dataset/Annotations/*.xml -o ./fixed/5.5 现象mosaic增强后出现“铁栏穿透猪身”的伪影原因mosaic将4张图拼接当两张图的铁栏位置重合时算法误判为连续栅栏导致猪体被“切割”。解决在ultralytics/data/augment.py中修改Mosaic类# 原始mosaic逻辑易产生栅栏伪影 # 新增栅栏区域mask对每张图检测竖直线条霍夫变换拼接时避开mask区 def _avoid_fence_artifact(self, img, labels): # 检测铁栏Canny霍夫直线 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) edges cv2.Canny(gray, 50, 150) lines cv2.HoughLinesP(edges, 1, np.pi/180, threshold100, minLineLength50, maxLineGap10) if lines is not None: fence_mask np.zeros(img.shape[:2], dtypenp.uint8) for line in lines: x1,y1,x2,y2 line[0] if abs(x1-x2) 10: # 竖直线 cv2.line(fence_mask, (x1,y1), (x2,y2), 255, 2) # 在mosaic拼接时对fence_mask0区域降权 return img * (1 - fence_mask/255*0.3) fence_mask//255*0.1 return img6. 农业场景模型验证用猪只计数误差率替代mAP的实战评估法6.1 为什么mAP在猪舍场景失效——从指标到业务的鸿沟在COCO上mAP0.5达0.85的模型放到猪舍实时计数时误差常超±15%。根本原因mAP只关心单帧检测而农业需求是连续视频流中的稳定计数。例如一只猪走过镜头mAP计为1次正确检测但业务需要知道“当前圈舍有23头猪”这要求模型在10秒内对同一目标不重复计数ID consistency且能处理进出栏门的遮挡。因此我们弃用mAP构建猪只计数误差率PCE, Pig Counting ErrorPCE |GroundTruth_Count - Model_Count| / GroundTruth_Count × 100%其中GroundTruth_Count由兽医人工点数每圈舍视频抽样30秒3人独立计数取中位数。6.2 PCE测试协议模拟真实部署的4阶段压力测试阶段测试内容通过标准工具静态验证单帧图计数9800张图全测PCE ≤ 5%yolo predict sourceimages/ save_txt 脚本统计动态验证30秒监控视频30fps输出每帧bbox连续10帧ID不跳变率 ≥ 92%DeepSORT 自定义ID校验光照鲁棒同一视频截取晨/午/暮三段各10秒三段PCE方差 ≤ 3.5%FFmpeg抽帧 时间戳对齐遮挡压力人工合成铁栏遮挡OpenCV叠加栅栏图层遮挡率30%时PCE ≤ 12%Python PIL合成我们用该协议测试YOLOv8n静态PCE 4.2%合格动态ID稳定率 89.7%不合格需加DeepSORT光照方差 2.1%合格遮挡PCE 14.3%不合格需加注意力机制6.3 从检测到计数三行代码实现轻量级计数器不依赖复杂ReID用YOLO原始输出简单规则达成92% ID稳定率# pig_counter.py import numpy as np from collections import defaultdict class PigCounter: def __init__(self, iou_thresh0.3, persist_frames15): self.trackers defaultdict(list) # id - [center_x, center_y, frame_id] self.iou_thresh iou_thresh self.persist_frames persist_frames def update(self, bboxes, frame_id): # bboxes: [[x1,y1,x2,y2], ...] centers np.array([(b[0]b[2])/2, (b[1]b[3])/2] for b in bboxes) if not self.trackers: for i, c in enumerate(centers): self.trackers[i] [c, frame_id] return len(centers) # IOU匹配简化版用中心点距离代替IOU active_ids list(self.trackers.keys()) matched set() for i, c_new in enumerate(centers): best_dist, best_id float(inf), -1 for tid in active_ids: c_old self.trackers[tid][0] dist np.linalg.norm(c_new - c_old) if dist best_dist and dist 50: # 50像素内认为同一猪 best_dist, best_id dist, tid if best_id ! -1: self.trackers[best_id] [c_new, frame_id] matched.add(best_id) # 清理过期tracker to_del [tid for tid, (_, t) in self.trackers.items() if frame_id - t self.persist_frames] for tid in to_del: del self.trackers[tid] # 新增未匹配目标 for i, c in enumerate(centers): if i not in matched: new_id max(self.trackers.keys() or [0]) 1 self.trackers[new_id] [c, frame_id] return len(self.trackers) # 使用示例 counter PigCounter() for frame_id, bboxes in enumerate(video_bboxes): # video_bboxes来自yolo predict count counter.update(bboxes, frame_id) print(fFrame {frame_id}: {count} pigs)从那以后我每次部署猪只检测模型都强制走一遍PCE四阶段测试而不是看mAP数字。因为兽医不会问‘你的mAP多少’只会指着屏幕说‘这头猪明明在你为啥没数到’——那个瞬间所有论文指标都得让位给真实的猪。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →