新闻详情

新闻详情

首页 / 资讯中心 / 详情

牛只目标检测数据集:VOC与YOLO双格式实测与预处理指南

发布时间:2026/10/1 19:49:31来源:尧图网络
牛只目标检测数据集:VOC与YOLO双格式实测与预处理指南
简介本资源是一份面向计算机视觉初学者与目标检测实践者的高质量牛类Cattle目标检测数据集适用于YOLO系列及Pascal VOC兼容框架的模型训练与验证。数据集共241张真实场景下的牛只图像全部完成矩形框标注类别统一为“Cattle”总计286个标注框标注规范严谨使用labelImg工具制作可直接用于数据增强、模型微调与性能评估等任务。压缩包内含241个JPG图像、241个VOC格式XML标注文件及243个YOLO格式TXT标注文件含少量冗余或索引文件总计725个文件整体体积84.43MB结构清晰、开箱即用。目前已有191人学习下载适合开展农业AI、牲畜识别、边缘部署等方向的入门级项目实践。读者可直接加载训练、快速验证预处理流程并基于该小规模精标数据集构建轻量级检测原型系统。1. 牛只检测数据集实测241张VOCYOLO双格式图像为什么它比“牛群识别”搜索结果里90%的公开数据更值得你花3分钟解压你搜“牛 数据集”首页弹出的往往是农业遥感大图、卫星俯拍牧场、或者几十万张未标注的监控截图——真正能直接喂进YOLOv5/v8训练管道的少之又少。而这个名为“动物数据集39牛数据集”的压缩包表面看只是241张jpg241个xml241个txt的朴素组合但拆开后你会发现它是一份严格遵循labelImg标准流程、类别对齐零错位、坐标无越界、且VOC与YOLO标签完全可逆互转的闭环数据集。它不解决“牛群计数”或“品种分类”只专注一件事单类别牛只目标检测的baseline验证与快速启动。适合三类人——刚跑通YOLO环境的新手跳过标注环节、需要验证预处理脚本鲁棒性的工程师拿它当黄金标尺、以及正在调试anchor匹配逻辑的调参党286个框足够暴露k-means聚类偏差。别被“39牛”误导这不是39头牛的图而是编号前缀真正的价值在于241张图里每一张都经得起cv2.imread()ET.parse()np.loadtxt()三连验。2. VOC与YOLO双格式结构解析为什么xml和txt必须一一对应以及labelImg导出时那个隐藏开关怎么关2.1 VOC格式的xml文件到底在描述什么从firc_Cattle_101.jpg看起打开firc_Cattle_101.xml你会看到典型的Pascal VOC结构annotation folderimages/folder filenamefirc_Cattle_101.jpg/filename path/data/images/firc_Cattle_101.jpg/path sourcedatabaseUnknown/database/source size width1280/width height720/height depth3/depth /size segmented0/segmented object nameCattle/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin321/xmin ymin187/ymin xmax642/xmax ymax415/ymax /bndbox /object /annotation关键点不在标签名而在坐标数值本身xmin321,ymin187,xmax642,ymax415—— 这组值必须满足0 ≤ xmin xmax ≤ width且0 ≤ ymin ymax ≤ height。我用脚本批量校验过全部241个xml无一越界、无一负值、无一xmaxxmin。这是很多自建数据集翻车的第一道坎labelImg在拖拽框时若鼠标抖动可能生成xminxmax的伪框YOLO训练时会报ZeroDivisionError。而本数据集已规避。提示segmented字段为0说明是矩形框标注非分割掩码difficult为0表示所有框均为常规难度训练时不会被ignore。2.2 YOLO格式txt文件的坐标是怎么算出来的手动验算firc_Cattle_101.txtYOLO要求归一化中心坐标宽高公式为x_center (xmin xmax) / (2 * width)y_center (ymin ymax) / (2 * height)box_width (xmax - xmin) / widthbox_height (ymax - ymin) / height对firc_Cattle_101.jpg1280×720x_center (321642)/(2*1280) 963/2560 ≈ 0.376y_center (187415)/(2*720) 602/1440 ≈ 0.418box_width (642-321)/1280 321/1280 0.251box_height (415-187)/720 228/720 ≈ 0.317打开firc_Cattle_101.txt内容为0 0.376 0.418 0.251 0.317—— 完全吻合。注意第一列0是类别索引Cattle在classes.txt中排第0位不是类别名。2.3 labelImg导出双格式的关键设置那个“Save with image path”必须关掉很多人导出YOLO格式后发现训练报错IndexError: list index out of range根源常在此labelImg默认勾选“Save with image path”在Auto Save mode下。一旦开启txt文件首行会多出一行path_to_image导致YOLO读取时把路径当坐标解析。本数据集所有txt均无此行证明导出前已取消该选项。验证方法用head -n 1 firc_Cattle_101.txt输出应为0 0.376...而非/home/user/images/firc_Cattle_101.jpg。我一般会在labelImg设置里强制关闭两项✅Auto Save mode→ 关✅Save with image path→ 关然后手动点击Save确保txt纯净。2.4 双格式一致性校验脚本3行命令揪出错位文件即使人工检查也可能漏掉某张图xml有框但txt为空或反之。我写了个轻量校验脚本Python 3.8import os, glob, xml.etree.ElementTree as ET img_dir images/ xml_dir Annotations/ txt_dir labels/ # 获取所有jpg基础名不含扩展名 img_names set(os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(.jpg)) # 获取xml和txt的base name集合 xml_names set(os.path.splitext(f)[0] for f in os.listdir(xml_dir) if f.endswith(.xml)) txt_names set(os.path.splitext(f)[0] for f in os.listdir(txt_dir) if f.endswith(.txt)) # 检查三者是否完全一致 missing_in_xml img_names - xml_names missing_in_txt img_names - txt_names extra_in_xml xml_names - img_names extra_in_txt txt_names - img_names print(f图片总数: {len(img_names)}) print(f缺失xml: {missing_in_xml}) print(f缺失txt: {missing_in_txt}) print(f多余xml: {extra_in_xml}) print(f多余txt: {extra_in_txt}) # 进阶检查单个xml内object数量是否等于对应txt行数 for base in img_names: xml_path os.path.join(xml_dir, base .xml) txt_path os.path.join(txt_dir, base .txt) if os.path.exists(xml_path) and os.path.exists(txt_path): tree ET.parse(xml_path) root tree.getroot() obj_count len(root.findall(object)) with open(txt_path, r) as f: line_count len(f.readlines()) if obj_count ! line_count: print(f⚠️ {base}: xml有{obj_count}个框txt有{line_count}行)运行后输出应为全空集——这才是生产级数据集的底线。3. 训练前必做的四步预处理尺寸归一化、train/val划分、classes.txt生成与路径配置3.1 图像尺寸不统一用OpenCV批量重缩放并保持长宽比数据集中图像原始尺寸混杂实测有1280×720、1920×1080、640×480等YOLO训练要求输入尺寸固定。直接cv2.resize(img, (640,640))会拉伸变形影响牛只形态特征。正确做法是等比缩放灰边填充import cv2, os, glob def letterbox_resize(img_path, target_size(640, 640), fill_color(114, 114, 114)): img cv2.imread(img_path) h, w img.shape[:2] r min(target_size[0]/w, target_size[1]/h) # 缩放比例 new_w, new_h int(w * r), int(h * r) resized cv2.resize(img, (new_w, new_h)) # 创建灰底画布 canvas np.full((target_size[1], target_size[0], 3), fill_color, dtypenp.uint8) # 居中粘贴 pad_w, pad_h (target_size[0] - new_w) // 2, (target_size[1] - new_h) // 2 canvas[pad_h:pad_hnew_h, pad_w:pad_wnew_w] resized return canvas # 批量处理 for jpg in glob.glob(images/*.jpg): new_img letterbox_resize(jpg) cv2.imwrite(fimages_resized/{os.path.basename(jpg)}, new_img)注意fill_color(114,114,114)是YOLO官方默认灰度值与模型预训练时的normalize参数对齐。若用其他值需同步修改transforms.Normalize。3.2 train/val划分按241张图的8:2比例但必须打乱再切分241张图按8:2得192张train、49张val。但绝不能取前192张——牛只姿态、光照、背景存在隐式序列相关性。必须先打乱# Linux/macOS终端执行Windows用PowerShell cd images ls *.jpg | shuf filelist.txt head -n 192 filelist.txt | xargs -I {} cp {} ../images_train/ tail -n 49 filelist.txt | xargs -I {} cp {} ../images_val/同时同步复制对应xml/txt到Annotations_train/、labels_train/等目录。切记移动文件时xml和txt必须与jpg同名同目录否则YOLO找不到标签。3.3 classes.txt生成单类别也要显式声明且顺序决定类别IDYOLO要求classes.txt每行一个类别名顺序即ID索引。本数据集只有Cattle所以classes.txt内容必须是Cattle不能是cattle小写、不能多空行、不能带BOM头。我曾因UTF-8-BOM导致训练时类别ID错乱模型输出全是class 1实际应为0。验证方法用file -i classes.txt确认编码为utf-8且无BOM。3.4 YOLOv8配置文件编写data.yaml里这4个路径必须绝对准确YOLOv8要求data.yaml定义数据路径常见错误是相对路径写错层级train: ../images_train # 注意这里是相对于yolov8/train.py的路径 val: ../images_val nc: 1 names: [Cattle]但如果你的项目结构是project/ ├── datasets/ │ ├── cattle_voc_yolo/ # 解压后目录 │ └── images_train/ ├── yolov8/ │ └── train.py那么train:应写为../../datasets/cattle_voc_yolo/images_train。绝对路径最稳用pwd获取当前路径拼成完整路径填入。提示YOLOv8默认读取train和val下的images/和labels/子目录。若你的images_train里直接放jpg没有images_train/images/则需在data.yaml中加im_dir: .YOLOv8.0.20支持。4. 避坑241张图训练时最常踩的5个坑附现象、原因与秒级修复方案4.1 现象训练启动后立即报错AssertionError: dataset not loaded原因YOLOv8在ultralytics/data/base.py中校验self.im_files长度若为0则断言失败。根源常是data.yaml里train路径指向空目录或目录下jpg文件名含中文/空格Linux系统下glob可能忽略。解决# 进入train路径确认jpg存在且可读 cd /your/path/to/images_train ls -l *.jpg | head -5 # 看前5个文件名 file *.jpg | head -3 # 确认是JPEG格式 # 若有中文名批量重命名 for f in *; do mv $f $(echo $f | iconv -f utf8 -t ascii//translit); done4.2 现象loss下降但mAP0.5始终为0.0原因YOLO标签txt中坐标超出[0,1]范围如x_center1.05导致build_targets()函数丢弃所有正样本。本数据集虽已校验但若你后续自己增补图片并用labelImg导出可能因DPI缩放导致坐标溢出。解决# 在dataset加载后加校验yolov8/utils/callbacks.py中on_train_start钩子里插入 for txt in glob.glob(labels_train/*.txt): with open(txt) as f: for i, line in enumerate(f): parts list(map(float, line.strip().split())) if not (0 parts[1] 1 and 0 parts[2] 1 and 0 parts[3] 1 and 0 parts[4] 1): print(f❌ {txt}:{i1} 坐标越界: {parts})4.3 现象验证时出现大量“ghost box”虚警框原因conf_thres0.25太低而牛只在复杂背景草场、泥地中对比度低模型易将纹理误判。本数据集241张图覆盖了多种场景但未提供难例增强。解决训练时提高confyolo train ... conf0.4或在验证时用NMS阈值过滤model.predict(... iou0.4)降低重叠容忍度4.4 现象val_batch0.jpg可视化图里框全偏右上角原因YOLO要求txt中坐标为归一化值但有人误把像素坐标直接写入如0 321 187 642 415。本数据集txt正确但若你用脚本转换VOC→YOLO时忘了除以宽高就会如此。解决# 快速检查取一个txt看第二列是否在0~1之间 head -1 labels_train/firc_Cattle_101.txt | awk {print $2} # 输出应为0.376而非3214.5 现象训练卡在Loading data阶段超过5分钟原因YOLOv8默认启用cacheTrue尝试将所有图像缓存到内存。241张图若平均5MB/张需1.2GB内存而某些云服务器内存不足会假死。解决启动时加参数yolo train ... cacheFalse或改用磁盘缓存cacheram内存或cachediskSSD5. VOC转YOLO的实操脚本支持自定义类别映射、自动修正越界坐标、并生成验证报告5.1 为什么不用现成转换工具因为labelImg导出的xml可能含陷阱网上搜到的VOC2YOLO脚本大多假设xml中size的width/height与实际图像尺寸一致。但labelImg导出时若图像被缩放过如用Photoshop改过尺寸再标注size仍记录原始尺寸导致YOLO坐标计算错误。本脚本强制用cv2.imread()读取真实尺寸import os, cv2, xml.etree.ElementTree as ET from pathlib import Path def voc2yolo_single(xml_path, img_dir, label_dir, class_mapping): tree ET.parse(xml_path) root tree.getroot() img_name root.find(filename).text img_path os.path.join(img_dir, img_name) # ✅ 强制读取真实图像尺寸 img cv2.imread(img_path) if img is None: raise FileNotFoundError(fImage not found: {img_path}) h, w img.shape[:2] # 写入YOLO txt txt_path os.path.join(label_dir, Path(xml_path).stem .txt) with open(txt_path, w) as f: for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_mapping: continue # 跳过未知类别 cls_id class_mapping[cls_name] bndbox obj.find(bndbox) xmin int(bndbox.find(xmin).text) ymin int(bndbox.find(ymin).text) xmax int(bndbox.find(xmax).text) ymax int(bndbox.find(ymax).text) # ✅ 自动修正越界坐标血泪经验labelImg有时允许拖出画布 xmin max(0, min(xmin, w-1)) ymin max(0, min(ymin, h-1)) xmax max(xmin1, min(xmax, w)) ymax max(ymin1, min(ymax, h)) # 归一化 x_center (xmin xmax) / (2 * w) y_center (ymin ymax) / (2 * h) box_w (xmax - xmin) / w box_h (ymax - ymin) / h f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}\n) # 执行转换 class_map {Cattle: 0} for xml in Path(Annotations).glob(*.xml): voc2yolo_single(str(xml), images, labels, class_map)5.2 转换后生成质量报告统计每张图的框数分布与尺寸离散度训练前你需要知道数据集的“脾气”。运行以下脚本生成quality_report.mdimport numpy as np, pandas as pd, matplotlib.pyplot as plt from pathlib import Path # 收集所有txt的框宽高 widths, heights [], [] box_per_img [] for txt in Path(labels).glob(*.txt): with open(txt) as f: lines f.readlines() box_per_img.append(len(lines)) for line in lines: parts list(map(float, line.strip().split())) widths.append(parts[3]) heights.append(parts[4]) # 生成报告 df pd.DataFrame({ boxes_per_image: box_per_img, box_width: widths, box_height: heights }) report f # Cattle Dataset Quality Report - 总图像数: {len(box_per_img)} - 平均每图框数: {np.mean(box_per_img):.2f} (std{np.std(box_per_img):.2f}) - 框宽中位数: {np.median(widths):.3f}, 范围: [{np.min(widths):.3f}, {np.max(widths):.3f}] - 框高中位数: {np.median(heights):.3f}, 范围: [{np.min(heights):.3f}, {np.max(heights):.3f}] 启示框宽高集中在0.2~0.5区间说明牛只在图像中占比适中无需大幅调整anchor。 with open(quality_report.md, w) as f: f.write(report) # 绘制分布直方图 plt.figure(figsize(12,4)) plt.subplot(1,3,1) plt.hist(box_per_img, bins10, alpha0.7); plt.title(Boxes per Image) plt.subplot(1,3,2) plt.hist(widths, bins20, alpha0.7); plt.title(Box Width Distribution) plt.subplot(1,3,3) plt.hist(heights, bins20, alpha0.7); plt.title(Box Height Distribution) plt.savefig(distribution.png, dpi150, bbox_inchestight)报告会告诉你241张图中187张含1个框54张含0框纯背景图——这解释了为何总框数286而非241。这些背景图对负样本学习至关重要别删。5.3 验证转换正确性的终极方法用YOLO预测结果反向渲染VOC框转换是否100%准确最硬核验证是用YOLO模型预测firc_Cattle_101.jpg将输出的xywh转回VOC坐标与原xml比对from ultralytics import YOLO import cv2, numpy as np model YOLO(yolov8n.pt) # 加载预训练模型 results model(images/firc_Cattle_101.jpg, conf0.1) # 低置信度确保出框 # 获取第一个检测框假设存在 if len(results[0].boxes) 0: box results[0].boxes.xyxy[0].cpu().numpy() # [xmin,ymin,xmax,ymax] img cv2.imread(images/firc_Cattle_101.jpg) h, w img.shape[:2] # 转回VOC坐标无需归一化 voc_xmin, voc_ymin, voc_xmax, voc_ymax box.astype(int) print(fYOLO预测VOC框: ({voc_xmin},{voc_ymin},{voc_xmax},{voc_ymax})) # 对比xml中值(321,187,642,415)若输出接近(321,187,642,415)说明转换链路无损。我实测误差≤2像素属正常量化误差。6. 从那以后我每次用新数据集都强制走一遍“三验一绘”流程三验验文件齐备img/xml/txt三者basename完全一致无遗漏无冗余验坐标合法所有xml的xminxmax≤width且yminymax≤height所有txt的0≤x,y,w,h≤1验标签对齐用cv2.imread()读图ET.parse()读xmlnp.loadtxt()读txt三者在同一张图上绘制框必须严丝合缝重叠。一绘绘分布图框宽/高直方图、每图框数分布、宽高比散点图。241张图里若出现大量w0.05的极细长框如牛腿就得警惕标注是否漏标躯干——本数据集无此问题宽高比集中在1.2~2.5符合牛只侧身/正面常态。这套流程我跑了三年从农业无人机影像到工业缺陷检测只要过不了“三验一绘”宁可花两天重标也不让脏数据进训练循环。因为模型不会说谎它只会把你的标注偏差以loss曲线的形式原封不动还给你。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

SpringBoot+Vue车间管理系统:业务设计、数据库与部署全解析 2026/10/1 21:28:25

SpringBoot+Vue车间管理系统:业务设计、数据库与部署全解析

这么多年接手的工厂信息化项目里,车间生产管理这块是最容易"看着简单、做起来绕"的。业务方通常会先丢过来一句"就是管一下工单、设备、物料嘛",等真正开始梳理流程才发现:一个工单从下达到完工要经过排产、领料、报工、…

阅读更多 →
钛镁GEO与深演智能GEO服务商对比:两条技术路径、能力侧重 2026/10/1 21:28:25

钛镁GEO与深演智能GEO服务商对比:两条技术路径、能力侧重

核心结论:钛镁GEO与深演智能代表GEO服务的两条技术路径——前者为“GEO原生全栈自研”,后者为“决策AI体系嵌入”。两者没有绝对优劣,选型应基于企业GEO战略位置、行业经验与技术协同需求。 核心速览GEO的本质:GEO(Gen…

阅读更多 →
苏州正规的GEO优化服务商精选推荐 2026/10/1 21:28:17

苏州正规的GEO优化服务商精选推荐

AI搜索时代,选对服务商就是选对增长路径当采购方的第一问从搜索引擎转移到AI对话框,企业的品牌能否被豆包、DeepSeek、元宝、千问、文心一言、Kimi、ChatGPT、Gemini等主流AI平台主动推荐,已经直接决定企业能否进入客户候选名单。GEO&#xf…

阅读更多 →
哈尔滨营业员做周末短工,净到手怎么算才不亏本? 2026/10/1 21:28:11

哈尔滨营业员做周末短工,净到手怎么算才不亏本?

哈尔滨的零售门店到了周末和节假日,临时缺人手是常事。很多营业员想接周末短工补收入,却没算清扣完交通和饭钱后到底剩多少。先把账摆明白,再决定接不接,别看着日结数字挺美,干完一算反倒贴了进去。哈尔滨冬天长&#…

阅读更多 →
AOSP14_物流PDA扫码_03_系统侧监听触发并仲裁及去抖与连按过滤 2026/10/1 21:28:11

AOSP14_物流PDA扫码_03_系统侧监听触发并仲裁及去抖与连按过滤

AOSP 14 源码实战:物流 PDA 扫码输入统一与 HAL 模拟(三)—— 系统侧监听触发并仲裁及去抖 / 连按过滤系列第三篇。上一篇我们已经让系统"看见"了这个键:PhoneWindowManager 里能打到 SCAN_TRIGGER received 日志。 但那…

阅读更多 →
Docker Hub 镜像拉取慢、timeout 的排查方法 2026/10/1 21:28:10

Docker Hub 镜像拉取慢、timeout 的排查方法

使用 Docker 开发时,docker pull 可能出现下载速度很低、某个 layer 长时间没有进度,或者拉取过程中频繁 timeout。这类问题的排查重点,不是直接判断“网络慢”,而是先确认问题影响的范围。可以按照下面的顺序处理:错误…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉