ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLOv5生猪检测数据集构建:从视频采集到标注划分的完整指南

YOLOv5生猪检测数据集构建:从视频采集到标注划分的完整指南 简介面向猪圈摄像头场景的目标检测数据集以YOLOV5标准目录格式整理包含生猪检测单类别pig适合计算机视觉初学者进行模型入门训练也适合农业智能化开发者快速验证检测算法。资源共2000个文件含1066个txt标签、933张jpg图像及1个可视化py脚本压缩包整体约97.43MB目录结构清晰无需额外格式转换即可接入YOLOV5流程。图像均为640-1080分辨率的RGB照片每张包含多个目标适合密集目标检测场景数据划分明确训练集929张、验证集136张对应标签txt文件一一配对并额外给出1类别txt文本信息类别定义一目了然。另附可视化py脚本随机传入一张图片即可自动绘制边界框并保存到当前目录开箱即用方便快速预览标注质量。目前已有609人学习下载适合需要真实养殖场数据、希望省去采集和标注环节的开发者直接使用。1. 目标检测数据集卡在目录格式猪圈摄像头下的单类生猪检测怎么搭在猪圈摄像头场景里做目标检测多数项目最先翻车的不是模型参数而是数据集没按YOLOv5目录格式整理。YOLOv5要求images与labels分开存放标签是txt每行写“类别 中心点x 中心点y 框宽 框高”坐标全部归一化到0-1之间图片与标签必须同名。猪圈摄像头固定机位、俯视视角猪群密集、遮挡多、昼夜光照差异大想做单类别的生猪检测得先把素材采集、标注规范和目录划分这三件事做对。下面就从监控视频素材一路拆到可直接开训的数据集适合已跑通yolov5、准备自己整数据的工程师和学生。2. 从监控视频到图片帧采集筛选与帧采样的三个原则很多教程上来就说“准备200张图就能训”但真正的问题是这200张图从哪来、怎么筛、怎么避免重复。猪圈摄像头一天24小时都在录素材并不缺缺的是有代表性、少冗余、能覆盖不同环境状态的帧。这一步做得越细后面标注越省力训练效果也越可控。2.1 采集策略覆盖昼夜、光照与地面状态变化猪圈画面和风景照不同大多数时间猪不动、镜头不动、亮度也不动真正让模型失效的是光照和姿态的切换。白天强光下猪身轮廓清晰黄昏时栏舍阴影拉长夜间切到红外模式后整幅画面变成灰白色调。模型如果只在一种光照下见过猪换个时段就容易漏检。常见做法是连续采集3到5天每天挑6到8个时段各录几分钟覆盖天亮、正午、傍晚、夜间红外几个关键时段。同时记录栏舍状态地面干燥、地面潮湿、刚清理完、有粪污覆盖这些都会改变目标周围的纹理。采集时镜头尽量保持俯视机位一旦选定就不要频繁移动让模型学习的是猪本身而不是特定角度的背景。采集完成后按视频文件名标记来源例如day01_day.mp4、day02_night.mp4。这个标记在后面划分训练集和验证集时非常关键能避免同一段视频的连续帧被分到两个集合里。2.2 帧采样与初筛按时间间隔抽帧别按帧号硬抽监控视频普遍是25帧每秒猪在栏舍里很多时候趴着不动如果按固定帧号每30帧抽1帧10秒视频能抽出将近10张几乎一样的图。这些重复图放进训练集本质上是让标注员把同一个框画好几遍模型却得不到新信息。我一般按时间间隔抽帧比如每5秒抽1帧写成脚本很快import cv2 import os video_path raw_videos/day01.mp4 out_dir raw_frames/day01 os.makedirs(out_dir, exist_okTrue) cap cv2.VideoCapture(video_path) fps cap.get(cv2.CAP_PROP_FPS) interval int(fps * 5) # 每5秒抽1帧 frame_idx 0 save_idx 0 while True: ret, frame cap.read() if not ret: break if frame_idx % interval 0: cv2.imwrite(os.path.join(out_dir, fday01_{save_idx:05d}.jpg), frame) save_idx 1 frame_idx 1 cap.release()这段脚本的逻辑是读入视频后先拿到帧率fpsinterval取fps乘5也就是5秒对应的帧数。每走到一个interval倍数就保存一帧文件名带来源前缀和序号。interval是主要调节参数想抽得密就把5改成3想省标注量就改成8或10。抽完帧后还需要人工初筛一轮把三类图删掉画面完全模糊的、镜头被猪或异物挡死的、人进栏舍后猪被挡掉大半的。初筛标准很朴素就是画面里能看清猪的轮廓。这个环节只删不补删完剩下的图才进入标注队列。2.3 图片数量定多少先定验证集再反推训练集单类别生猪检测里真正决定数据量的是实例数而不是图片数。一张俯视猪圈图往往有5到15头猪按平均8头算300张图就能提供2400个实例足够支撑一个起步模型。如果每张图只有一两头猪那1000张图也未必够。我的习惯是先把验证集定下来单独留出60到100张要求覆盖白天、黄昏、夜间和不同栏舍数量不需要多但来源必须和训练集尽量分开。验证集不独立后面的mAP就是自欺欺人。训练集在验证集定好之后再补齐总图量建议往400到500张走这样即使抽帧后仍有些冗余训练时也能承受。这里不用一次性追求几千张单类别任务里先把实例数做够、来源做分散比堆砌重复帧更实际。至于要不要单独留测试集建议预留10%左右等模型训练完再拿出来做最终验收。3. 用LabelImg产出YOLO格式标签单类别生猪的标注规范与坐标自查图片备好后下一步是把每张图里所有可见的猪用矩形框标出来。标注工具的选型我很务实能用LabelImg直接出YOLO格式txt就不去绕路用其他工具。LabelImg是开源工具输出格式里自带YOLO省去JSON转txt的坐标换算环节。3.1 安装LabelImg并设置单类别安装很简单在命令行里执行pip install labelimg labelimg打开后左侧标签列表先输入类别名pig并添加再把保存格式选成YOLO。这样每保存一张图软件会在图片同目录生成一个同名txt内容就是YOLO标签。用其他标注平台也可以但导出通常是JSON或XML还需要写脚本转成“类别中心点宽高”的txt多一次坐标计算就多一次出错机会没必要。标注时有两个操作习惯值得养成一是每标完一张就立即保存不要攒一批再存软件卡死时能少丢很多工作量二是把画布拉开到200%再标猪只密集时尤其需要放大否则很容易把相邻的猪框到一起。3.2 标注规范整猪框选只保留一个类别单类别的好处是不用纠结“这是猪还是另一头猪”难点集中在框的范围。我常用的规则是把可见的整头猪框进去矩形四边贴着猪身外轮廓留一点余量但不故意放大。两头猪挨得再近也要分别框两个矩形允许两个框轻微重叠绝不允许一个框装两头。被遮挡的猪处理起来要立一个明确规则可见面积大于整头猪约三分之一时按可见范围把整猪框出来小于三分之一时不框。这条规则看着随意其实是在控制标签中心点的质量。YOLOv5训练时会把标签框的中心点当作目标位置一个框里装了两头猪中心点落在两头猪之间模型学到的是个模糊位置后期输出就会是一个大框包住好几头。边界情况的处理可以对照这张表执行场景标注动作两头猪紧贴分别标两个框允许轻微重叠一头猪被挡掉一半按可见范围框整猪只露出头部不标避免引入过小且形状失真的目标远处小猪只有十几个像素放大画布到200%后再确认不可见就不标3.3 标签一行五个数字的含义与快速自查YOLO格式的txt里每一行对应一个目标下面这行就是一头猪的标签0 0.31250 0.48148 0.10417 0.13889第一个数字0是类别编号单类别场景下永远是0。后面四个数字依次是框中心点的x、y坐标、框的宽、框的高全部做了归一化取值范围在0到1之间。归一化计算方式很简单中心点像素x除以图片宽度中心点像素y除以图片高度框像素宽度除以图片宽度框像素高度除以图片高度。举例来说1920×1080的图上有一个框中心像素在(600, 520)宽200、高150那这行就是“0 600/1920 520/1080 200/1920 150/1080”。标注阶段要特别注意不要把像素坐标直接写进txt也不要混入目标名称。写完一批标签后我习惯随机抽20张图把txt里的一行行数字换算回图上叠在原图上看一遍。这个动作只需要几分钟却能直接暴露手滑标错的大框和越界坐标。4. 目录格式搭建与数据划分images/labels分离与80/10/10脚本图片和标签都有了还差最后一步组织工作把它们按YOLOv5目录格式摆好并划分成训练集、验证集和测试集。这一步看起来只是移动文件实际是训练能否顺利跑起来的前提YOLOv5对目录结构的约定相当严格。4.1 YOLOv5期望的目录结构与data.yaml写法YOLOv5在读取数据集时会固定从两个子目录里找图片和标签images目录放图片labels目录放同名txt。训练时它还会做一层隐式关联——拿到一张图片路径后自动把路径里的images替换成labels去对应位置找标签文件。所以目录结构必须和下面这张表对齐目录/文件作用dataset/images/train训练图片jpg或png均可dataset/labels/train训练标签与图片同名dataset/images/val验证图片dataset/labels/val验证标签dataset/images/test测试图片可选项dataset/labels/test测试标签可选项dataset/pig.yaml数据描述文件接着是data.yaml的写法path: /home/me/pig_dataset train: images/train val: images/val test: images/test nc: 1 names: 0: pig这里有一个容易翻车的地方train、val、test这三项只写images子目录不写labels。因为YOLOv5会自动把images替换成labels去找标签如果在yaml的train里写labels/train训练启动时它去找labels/labels/train结果全是空路径日志里只会出现“找不到标签”的警告。path建议直接写绝对路径换机器后虽然要改一次但比相对路径在部分配置下解析出错更好排查。4.2 用划分脚本完成80/10/10拆分目录结构定好后用脚本一次性完成划分。下面这段脚本会把一个平铺的图片目录按80/10/10拆成train/val/test并把同名标签同步拷过去import os import random import shutil src_images all_images # 所有筛选好的图片 random.seed(42) imgs [f for f in os.listdir(src_images) if f.lower().endswith((.jpg, .jpeg, .png))] random.shuffle(imgs) total len(imgs) n_train int(total * 0.8) n_val int(total * 0.1) train_imgs imgs[:n_train] val_imgs imgs[n_train:n_train n_val] test_imgs imgs[n_train n_val:] def copy_to(img_name, subset): img_src os.path.join(src_images, img_name) label_src img_src.rsplit(., 1)[0] .txt img_dst_dir fdataset/{subset}/images label_dst_dir fdataset/{subset}/labels os.makedirs(img_dst_dir, exist_okTrue) os.makedirs(label_dst_dir, exist_okTrue) shutil.copy(img_src, os.path.join(img_dst_dir, img_name)) shutil.copy(label_src, os.path.join(label_dst_dir, img_name.rsplit(., 1)[0] .txt)) for img in train_imgs: copy_to(img, train) for img in val_imgs: copy_to(img, val) for img in test_imgs: copy_to(img, test)脚本逻辑很直接先把图片列表打乱按比例切成三段再把图片和同名标签一起拷到对应目录。这里我特意用shutil.copy而不是shutil.move复制一份进dataset目录原始素材保留在原地。标注数据整理过程中很可能反复调整筛选标准原始图库不破坏才有后悔药可吃。标签查找这里用img_src.rsplit(., 1)[0]来去掉扩展名再拼上.txt是为了适应jpg、png混用的情况。唯一要注意的是图片和标签必须在同一层目录、同名否则拷贝过去后YOLOv5会在images里找到图片却找不到对应的labels文件。4.3 划分比例与随机种子两个容易被忽视的细节80/10/10是单类别任务里比较务实的选择。训练集拿大头验证集用来做早停和选模型测试集留到最后一轮验收。如果总图量不足300张可以调整成85/12/3测试集只留十几张图作为最终跑视频前的最后一道检查。随机种子建议固定。脚本里写了random.seed(42)每次跑出来的划分结果一致标注返工后重跑目录不会出现“上次那张图在train这次跑到val”的问题。但比随机种子更关键的是划分前先按视频来源分组。我的做法是抽帧时文件名带day01、day02这种前缀划分时先按前缀把帧分成组再组间随机划分保证同一段视频的连续帧不会同时出现在训练集和验证集里。如果素材里混了同一段视频前后5秒的帧验证指标会虚高真实场景一测就露馅。5. 数据集常见问题与避坑清单五条高频返工记录数据集做得多了返工最多的永远不是画框本身而是画框之前和之后那些没人提前说的细节。下面五条是我在这个猪圈数据集上真实踩过的坑每一条都按“现象、原因、解决”拆开讲排查时能直接照着做。5.1 标签文件与图片文件名不一致样本被静默跳过的三个信号现象训练日志没有报错loss也在降但验证集召回率一直偏低打开检测结果发现有几张图永远没有预测框。原因图片从别的项目拷贝过来后做过重命名比如从“IMG_001.jpg”改成了“day01_00001.jpg”但同名txt没有同步改名。YOLOv5找不到标签时会把这张图当作背景图处理不报错、不中断。解决在数据集上跑一遍配对检查找出缺失标签的图import os img_dir dataset/images/train label_dir dataset/labels/train for name in os.listdir(img_dir): if not name.lower().endswith((.jpg, .jpeg, .png)): continue label_path os.path.join(label_dir, name.rsplit(., 1)[0] .txt) if not os.path.exists(label_path): print(missing label:, name)这段脚本用图片名去掉扩展名再拼.txt去查标签文件凡是打印出来的图都要处理要么补标签要么从数据集里删掉。训练集里留着一张没标签的“背景图”等于主动告诉模型“画面上没有任何猪”对密集猪圈场景的漏检影响很明显。5.2 连续帧数据泄漏验证集mAP虚高的假象现象训练完mAP0.5能到0.95但把模型接到一段没参与训练的新视频上漏检明显变多表现远不如指标那么漂亮。原因划分train/val时直接对全部图片随机shuffle。同一个5秒片段里的几帧画面几乎一样被同时分进了训练集和验证集验证集等于把背过的答案再考一遍。解决抽帧时文件名带视频来源前缀划分前先按前缀分组组间再做随机划分。更彻底的办法是验证集单独选自另一个栏舍或另一天的视频训练集完全不碰这些帧。前者能发现同源画面的漏检问题后者才能证明模型见过的不只是同一个猪圈。5.3 夜间红外帧漏标与错标低照度图像的补救流程现象白天画面里检测正常一到夜间红外模式就漏检而且漏的是人眼也容易忽略的暗部猪只。原因红外图像对比度低猪和栏舍背景都是灰白色调标注员盯久了注意力下降漏标率比白天高。人眼都没看见的目标模型自然学不会。解决夜间帧单独抽出来先用CLAHE做一次对比度增强在增强图上完成标注再把同组坐标写回原图。标注时不要把增强图和原图混着标否则同一批标签的视觉基准不一致。标完后再让另一个人只看原图快速过一遍重点查漏标夜间数据的漏检能明显降下来。5.4 密集场景一个框框两头猪目标中心点错乱的根源现象模型在猪群密集时输出一个很大的矩形把两三头猪包在同一个框里置信度还不低。原因标注阶段为了赶进度相邻的两头猪被画进了一个框。YOLOv5把标签框中心点当目标位置一个框里有两头猪中心点落在中间空隙模型学出来的位置始终偏在猪群中央。解决两猪紧贴时分开标两个框允许两个矩形轻微重叠不许合并。落框时如果发现框比旁边同类目标的典型尺寸大出一截停下来放大画布确认是不是包含了多目标。这个检查动作放在标注中段做比事后返工省人力。标注规则事先写进标注说明里比临场发挥可靠得多。5.5 标签坐标越界或过小训练loss异常的前置排查现象训练过程中loss突然变成nan或者某个目标尺寸特别小的类别AP一直是0。原因标注时鼠标拖出了画布边缘生成的归一化坐标大于1或小于0也可能是画了只有几个像素的小框归一化后宽高小于0.01模型根本学不到有效特征。解决统一跑一次标签体检把越界和过小目标找出来import glob bad [] for txt in glob.glob(dataset/labels/**/*.txt, recursiveTrue): with open(txt, r) as f: for line in f: parts line.split() vals list(map(float, parts)) if len(parts) ! 5: bad.append((txt, 字段数不对)) break if not (0 vals[1] 1 and 0 vals[2] 1): bad.append((txt, 中心点越界)) break if vals[3] 0.01 or vals[4] 0.01: bad.append((txt, 目标过小)) break for item in bad: print(item)这段脚本遍历所有标签txt逐个检查五个字段是否齐全、中心点是否在图片范围内、框宽高是否小于图片尺寸的1%。对于越界的坐标要回原图上修正对于过小目标建议直接删掉对应那行。物理上真实存在但只有几个像素的小猪等模型在更大分辨率上见到再处理比硬塞进640分辨率下更靠谱。6. 训练前的最后检查与首次epoch排查一条命令暴露数据问题数据集整理到这里距离训练只有一步。但直接跑train.py之前我建议先做一次标签体检再把首次epoch日志当作数据质量的最后一道反馈。6.1 训练前先看两个统计实例数与目标尺寸分布把第5章的配对检查和坐标体检脚本各跑一遍确认没有缺失标签、没有越界坐标。然后做一次最简单的统计统计每张图的实例数量以及所有框的宽高分布。平均每张图不足3个框说明漏标严重这种数据集直接训练模型会把猪圈当成“大多数时候没有猪”的地方。框宽高普遍小于图片尺寸的0.03则说明小目标占比高--img参数需要从640提到960而不是硬用640硬扛。6.2 首次epoch日志与训练后实况验收体检通过后用这条命令启动训练python train.py --data pig.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --device 0 --patience 20参数选择基于单类别猪圈场景具体如下参数建议值说明--img640目标整体偏大就够用小目标多时改960--batch168G以下显存降到8--epochs100单类别任务常用区间配合早停--patience20连续20轮验证指标不涨就提前停首次epoch里最该看的是训练日志中的loss曲线和train batch自带的可视化标签框。loss首轮在0.1以上是正常的但如果loss直接nan或者可视化标签框位置明显错乱说明标签坐标转错了立刻停比等100轮更划算。训练结束后看验证集的mAP0.5单类别场景下0.9以上才算及格再看混淆矩阵确认有没有系统性漏检。想看模型到底聚焦在哪里可以用yolov5的gradcam脚本看特征图和热力图判断模型是在看猪身还是在学栏舍纹理。最后拿一段完全没参与训练的视频跑detect.py肉眼确认输出框贴合度。我最早做这个数据集时重做了两遍训练才搞明白问题不在模型全在标注标签和图片没对上、黑夜漏标、划分时连续帧泄漏。先把这些坑排掉yolov5训练自己的数据集才有意义。希望帮到你。本文还有配套的精品资源点击获取
返回列表