尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
VOC转YOLO格式与猪只检测:数据集清洗及YOLOv8训练实战
简介面向计算机视觉目标检测实践场景的猪只图像标注数据集包含约634张真实场景猪图片标注类别为pig已同时提供VOC与YOLO两种格式的标注文件可直接用于目标检测模型的训练、验证与算法入门实验也可用于猪只计数、养殖环境监测等相关任务。压缩包共1903个文件内含635个txt、634个xml与634个jpg其中jpg为原始图像xml为VOC格式标注txt为YOLO格式标注资源以三个文件夹分别存放图片、xml与txt文件名按pig_编号统一编排解压后即可通过labelImg打开查看标注框位置与类别信息方便匹配YOLO、SSD、Faster R-CNN等主流检测框架。资源包大小约229.59MB已有110人浏览学习适合学习者练习标注规范、调试检测流程或扩充自定义数据集。整理者专门说明了标注边界选取、目标全量标注与一致性检查等原则用户可在此基础上进一步校验标签质量也可直接作为模型训练的初始数据节省自行采集图片与手工标注的时间成本。1. 猪数据集标注的起点先看清 VOC 和 YOLO 的差异做猪只检测的工程师基本都会撞上同一个问题标注格式不统一。VOC 把目标框写在 XML 里YOLO 则是每张图片配一个同名 txt坐标全部归一化到 0 到 1。拿到一份 634 张左右的猪数据集第一件事不是急着训练而是先理清格式、验干净数据否则后面跑出来的 mAP 没有参考价值。这篇文章按「格式差异 → 转换脚本 → 数据清洗 → 训练参数 → 质量验证」推进读完就能把 VOC 标注转成 YOLO 格式并跑通训练适合刚接手标注数据、准备训练检测模型的算法工程师。2. VOC 与 YOLO 格式的字段差异和转换脚本2.1 VOC 的 XML 里到底存了什么VOC 格式源自 PASCAL VOC 目标检测挑战赛每张图片配一个同名 XML 文件。XML 顶层有 folder、filename、source 和 size 节点其中 size 记录图片宽高和通道数转换时务必读到因为 YOLO 的归一化坐标依赖真实像素尺寸。每个目标框在 object 节点下包含 name类别名、truncated目标是否被截断、difficult是否难以识别和 bndboxxmin、ymin、xmax、ymax。最容易忽略的是 truncated 和 difficult 两个布尔字段。difficult1 的框在 VOC 官方评估中不计入但直接转 YOLO 后这些框会变成普通正样本相当于往训练集里塞噪声。truncated 表示猪只被栅栏或同伴遮挡这类框要不要保留取决于推理场景如果最终检测的是圈舍内被部分遮挡的猪保留反而能提升鲁棒性。一个典型的 XML 结构如下annotation filenamepig_001.jpg/filename size width1280/width height720/height depth3/depth /size object namepig/name truncated1/truncated difficult0/difficult bndbox xmin120/xmin ymin80/ymin xmax600/xmax ymax450/ymax /bndbox /object /annotation这段 XML 描述了一张 1280x720 的猪舍图片框住左上角起点为 (120, 80)、右下角为 (600, 450) 的一头猪。解析时注意 bndbox 下四个值都是像素坐标换算顺序是先取出来、后归一化不能反过来先归一化再取中心否则会得到错误结果。2.2 YOLO 归一化坐标换算公式与常见坑YOLO 的 txt 标注每行对应一个框格式是class_id x_center y_center width height后四个值全部相对图片宽高归一化。换算公式如下x_center (xmin xmax) / 2 / img_widthy_center (ymin ymax) / 2 / img_heightwidth (xmax - xmin) / img_widthheight (ymax - ymin) / img_height这里有几个绕不开的坑。第一除数是图片的实际宽高不是 XML 里声称的值转换前最好用 PIL 或 cv2 重新读一次确认防止标注软件把 size 写错。第二归一化后的 width 和 height 允许大于 1比如目标顶到图片边缘且框画大了转换脚本不用强制裁剪但要留到校验阶段标记出来。第三class_id 从 0 开始计数类别名列表一旦定序就不能变训练和推理必须用同一份顺序。提示转换前用第三方库重新读取图片宽高以实际读取值为准。634 张图里只要有一张 XML 的 size 和实际不符对应的目标框就会整体偏移。2.3 写一个可靠的 VOC 转 YOLO 脚本常见做法是把 VOC 转 YOLO 写成独立脚本后续每批新标注都复用。我一般这样写import os import xml.etree.ElementTree as ET CLASS_NAMES [pig] # 索引即 class_id顺序不可随意调整 def voc_to_yolo(xml_path: str, out_dir: str) - None: tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) txt_name os.path.splitext(os.path.basename(xml_path))[0] .txt lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLASS_NAMES: continue # 不在类别表中的目标直接跳过 cls_id CLASS_NAMES.index(name) bb obj.find(bndbox) x1 float(bb.find(xmin).text) y1 float(bb.find(ymin).text) x2 float(bb.find(xmax).text) y2 float(bb.find(ymax).text) x_center ((x1 x2) / 2) / img_w y_center ((y1 y2) / 2) / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) if lines: # 空标注不生成文件避免误判为遗漏 with open(os.path.join(out_dir, txt_name), w, encodingutf-8) as f: f.write(\n.join(lines)) xml_dir annotations_voc yolo_dir labels_yolo os.makedirs(yolo_dir, exist_okTrue) for fname in os.listdir(xml_dir): if fname.endswith(.xml): voc_to_yolo(os.path.join(xml_dir, fname), yolo_dir)逻辑说明ElementTree 解析 XML 后先取图片宽高再遍历 object 节点每个框先核对类别名再取 bndbox 角点按 2.2 的公式换算中心点和宽高。输出坐标保留 6 位小数足够 YOLO 训练使用写得更长只会增加文件体积。空标注不生成文件这个细节很重要否则校验阶段无法区分「标注真的为空」和「转换过程漏了」。唯一要改的参数是 CLASS_NAMES转换前务必和标注软件里的类别拼写逐一比对大小写不一致都会导致框被静默丢弃。3. 634 张图的清洗、校验与训练集划分3.1 一致性检查图片和标注对不上是头号问题634 张的规模不大不小手工逐张检查不现实全自动又容易漏所以先跑一轮基础一致性检查图片能不能打开、每张图是否有对应标注、标注内容是否为空。三类问题分开统计再决定怎么处理。import os from PIL import Image img_dir images label_dir labels_yolo broken, empty, mismatch [], [], [] for fname in sorted(os.listdir(img_dir)): if not fname.lower().endswith((.jpg, .jpeg, .png)): continue label_path os.path.join( label_dir, os.path.splitext(fname)[0] .txt) try: img Image.open(os.path.join(img_dir, fname)) img.verify() except Exception: broken.append(fname) continue if not os.path.exists(label_path): mismatch.append(fname) continue with open(label_path) as f: if not f.read().strip(): empty.append(fname) print(损坏图片:, len(broken), broken) print(缺标注:, len(mismatch), mismatch) print(空标注:, len(empty), empty)脚本把问题拆成三类损坏图片直接删掉或重新导出缺标注的图数量少就删数量多说明转换路径有问题要回查 2.3 的脚本空标注要区分场景图片里确实没有猪可以当作背景负样本保留本该有猪却被漏标就得补标。注意 PIL 的 verify() 只验证文件结构完整不解码全部像素如果怀疑有加载后花屏的图需要再补一层 cv2.imread 检查或直接人工抽查。3.2 可视化回看是标注校验的地基脚本只能查格式查不了语义错误。634 张图里最常见的标注问题是框大了一圈、漏了角落的猪、把两只相邻的猪画成一个框。要抓这类问题正确姿势是把标注框画回图上随机抽几十张拼接成网格图一次看几十张。下面用 OpenCV 画框不引入额外标注工具import cv2 import os import random img_dir images label_dir labels_yolo def draw_boxes(img_path, label_path): img cv2.imread(img_path) h, w 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, bw, bh map(float, parts) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) return img files [f for f in os.listdir(img_dir) if f.lower().endswith((.jpg, .png))] random.seed(42) sample random.sample(files, min(30, len(files))) tiles [] for fname in sample: label os.path.join( label_dir, os.path.splitext(fname)[0] .txt) tiles.append(draw_boxes(os.path.join(img_dir, fname), label)) rows [] for i in range(0, len(tiles), 5): row cv2.hconcat( [cv2.resize(t, (320, 240)) for t in tiles[i:i 5]]) rows.append(row) grid cv2.vconcat(rows) cv2.imwrite(check_grid.jpg, grid) print(网格图已保存: check_grid.jpg)逻辑说明把 YOLO 归一化坐标乘回图片宽高得到像素坐标后画矩形框。随机种子固定为 42保证每次抽样的图一致方便后续和标注同学按编号对齐讨论。参数上缩放尺寸 320x240 和每行 5 张可以按需调整重点是抽样要随机不要只挑看着清楚的图否则校验结果偏向乐观。3.3 634 张的训练/验证/测试划分目标检测对划分比例的一个常见约束是图片数量越少验证集占比越高。634 张按 8:1:1 划分大约是 train 508、val 63、test 63。划分时不要按文件夹直接切因为原始数据可能按拍摄时间或猪舍分组连续帧高度相似直接切会让验证集和训练集高度重叠指标看起来虚高。划分数量用途train508训练主体依赖数据增强提升泛化val63早停、学习率调整、选 best 权重test63最终评估整个训练过程中一次都不要碰划分脚本要固定随机种子保证可复现import os import random import shutil src_img images src_lbl labels_yolo random.seed(42) files sorted(os.listdir(src_img)) files [f for f in files if f.lower().endswith((.jpg, .jpeg, .png))] random.shuffle(files) n len(files) n_val int(n * 0.1) n_test int(n * 0.1) val_files files[:n_val] test_files files[n_val:n_val n_test] train_files files[n_val n_test:] for split, flist in [(train, train_files), (val, val_files), (test, test_files)]: os.makedirs(fimages/{split}, exist_okTrue) os.makedirs(flabels/{split}, exist_okTrue) for f in flist: shutil.copy(f{src_img}/{f}, fimages/{split}/) lbl f{src_lbl}/{os.path.splitext(f)[0]}.txt if os.path.exists(lbl): shutil.copy(lbl, flabels/{split}/) print(ftrain{len(train_files)} val{len(val_files)} test{len(test_files)})这段脚本的关键点是把「随机打乱」放在「划分」之前并且使用固定随机种子。如果 634 张图里某个猪舍的数据特别多随机划分仍可能让同一场景同时出现在 train 和 val 里更严格的方案是按猪舍 ID 分组划分那需要数据集本身就带场景信息。4. 用 YOLOv8 训练猪检测模型的关键参数4.1 目录结构和 data.yaml把第 3 章划分出的目录整理成 Ultralytics 默认的布局images 和 labels 同级各自按 train、val 分子目录。图片文件名和标签文件名必须一致不含扩展名YOLOv8 训练时会自动在 labels 目录里根据图片名查找同名 txt。pig_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── pig.yamldata.yaml 内容如下path: /data/pig_dataset train: images/train val: images/val nc: 1 names: 0: pigpath 建议写绝对路径避免相对路径在不同机器上失效。nc 必须和 names 列表长度一致这里只有一个猪类别所以 nc 填 1。如果后续想加「母猪」「仔猪」等类别要回到转换脚本里同步更新 CLASS_NAMES再重新生成所有 txt。4.2 训练命令与关键参数说明634 张数据量不大不建议一上来就训练 YOLOv8l 或 x 版本先用 s 甚至 n 跑通流程确认数据没问题再升级模型。常用训练命令如下pip install ultralytics yolo detect train datapig.yaml modelyolov8s.pt \ epochs150 imgsz640 batch16 \ patience30 projectruns namepig_detect参数含义和推荐值整理如下参数推荐值说明modelyolov8s.pt小数据量用 s 起步n 更省显存epochs150配合早停一般 100 轮内收敛imgsz640尽量和标注图片原始分辨率一致batch168GB 显存降为 816GB 可用 16patience30val 指标连续 30 轮不提升就停workers4数据量小IO 压力不大4 足够imgsz 这个参数经常被忽略。如果原始图片是 1280x720标注时人工框选的分辨率也是 1280那 imgsz 用 640 等于强制缩放到一半再训练猪只目标本来就小缩放后可能只剩十几个像素检测效果会明显变差。可以先跑一轮 yolo detect val 检查框尺寸分布再决定 imgsz 用 640 还是 960。注意不要同时调多个超参数。634 张数据的一次完整训练只要十几分钟先固定 imgsz、batch、model只动 epochs 和 patience看收敛情况再决定下一步。4.3 训练过程看什么指标训练开始后关注两类东西损失曲线和验证指标。yolo 命令会在 runs/pig_detect 下输出 results.png重点看 val/box_loss 和 val/cls_loss。如果 train_loss 持续下降而 val_loss 先降后升说明过拟合此时加大 hsv_h、hsv_s 等增强参数或者增加 fliplr 翻转比例比直接加数据更便宜。训练结束后best.pt 对应的指标才是选型依据。634 张的猪检测任务如果 mAP50 能到 0.85 以上说明标注质量和数据分布都正常如果 val 集 mAP 很高但 test 集明显偏低要怀疑 3.3 的划分泄漏问题而不是模型问题。跑完一次后把 results.png 里的 mAP50-95 和 mAP50 记下来后续每次改动只允许一个变量变化否则没法归因。5. 用预测覆盖图反向排查标注错误训练本身也是一种标注质量检查手段。用 best.pt 对 val 集做推理把预测框和真值框叠加在同一张图上绿色画真值框红色画预测框一眼就能看出哪些标注有问题。yolo predict modelruns/pig_detect/weights/best.pt \ sourceimages/val \ projectverify \ save_txtTrue \ conf0.1 \ iou0.5conf 降到 0.1 是关键目的是让模型尽量多输出候选框宁可多预测也不漏这样对比真值时容易发现漏标。然后在 3.2 的 draw_boxes 基础上加一个红色预测框图层或者直接用 predict 输出的图片配合 save_txt 生成的坐标文件做判断。判读规则如下覆盖图特征对应的标注问题绿色真值框周围无红色框该样本漏标或小目标极难检测红色框堆叠两三个以上目标重叠严重需检查真值框是否合并了多头猪绿色框比红色框大 30% 以上标注框包含过多背景建议收窄某张 val 图全部无预测图片风格和训练集差异过大检查是否混入了异常帧循环这个流程时每轮只修正最明显的几十个框改完重新训练再预测两轮之后标注质量通常就稳定了。最后一轮建议把 test 集也过一遍预测但只看不改因为 test 集一旦参与修标就不再是干净的最终评估数据。整个过程记住一个原则模型不是用来替代标注的而是用来帮标注的人把注意力放在最可疑的样本上。本文还有配套的精品资源点击获取
RELATED

相关推荐

Matlab双层优化实现分布式光伏储能选址定容与配电网优化

Matlab双层优化实现分布式光伏储能选址定容与配电网优化

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

📅 2026/9/15 2:39:03
Linux挂载完全指南:从mount原理到fstab与NFS/CIFS实战

Linux挂载完全指南:从mount原理到fstab与NFS/CIFS实战

我遇到过不少这样的情况:朋友刚买了台服务器,或者自己装了台CentOS,插了一块数据盘,df -h一看,新盘没出现,张口就问“是不是系统没识别到硬盘”。其实识别到了和挂载了是两码事。在Linux里,一块…

📅 2026/9/15 2:34:03
STM32F103点灯实战:Keil5.38+CubeMX6.12硬核入门

STM32F103点灯实战:Keil5.38+CubeMX6.12硬核入门

1. 这不是“又一个STM32教程”,而是铁头山羊式入门的真实切口“铁头山羊STM32入门教程【新版】”——看到这个标题,你大概率会下意识点开,然后在前30秒内判断:这到底是真干货,还是又一个套壳搬运的“抄作业合集”&…

📅 2026/9/15 2:34:03
MORE NEWS

更多资讯

📰

ESP32蓝牙Beacon测距实战:RSSI标定与环境建模

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

📰

OpenPose姿态估计实战:PAF关键点匹配与跌倒预警系统实现

简介:基于OpenPose卷积神经网络的人体姿态识别及预警系统资源包,面向深度学习、计算机视觉方向的在校生与开发者,覆盖从模型训练、姿态关键点识别到异常预警的完整技术链路,可直接用于毕业设计、课程设计或项目前期验证。压缩包共…

📰

ResNet50特征提取+逻辑回归:轻量级猫狗分类实战

简介:本资源是一份面向深度学习初学者与计算机视觉实践者的Python源码案例,聚焦于使用预训练ResNet50模型提取猫狗图像特征,并结合逻辑回归完成二分类任务,解决经典图像识别入门问题。资源共43个文件,包含25个核心Pyth…

📰

基于1000张标注图像的钓鱼人员检测:YOLOv8训练全流程解析

简介:面向钓鱼场景的目标检测标注数据集,适用于计算机视觉入门及进阶开发者,可用于训练和评估能够识别岸边钓鱼人员的检测模型。压缩包仅41.55MB,却包含1000张jpg图像与1000个xml标注文件,合计2000个文件;图…

📰

AI Coding实战:从需求拆解到部署上线的全流程打法

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

📰

新型非易失性存储器如何破解GX Works2存储瓶颈

1. 为什么“新型非易失性存储器”正在悄悄改写硬件底层逻辑你有没有遇到过这样的场景:一台工业PLC设备在连续运行72小时后,突然报出“GX Works2 存储器空间或桌面堆栈不足,因此无法启动”?不是软件崩溃,不是电源异常&a…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬