红花目标检测数据集:VOC、COCO、YOLO三格式标签与YOLOv8训练全流程指南

发布时间:2026/10/10 18:08:13
红花目标检测数据集:VOC、COCO、YOLO三格式标签与YOLOv8训练全流程指南
简介面向目标检测学习与研究者的YOLO红花目标检测数据集基于真实场景高质量图片制作使用LabelImg标注标注框质量高。包内包含1000张红花图片同时提供voc(xml)、coco(json)、yolo(txt)三种格式标签分别存放于不同文件夹可直接用于YOLO系列模型训练免去格式转换的麻烦。压缩包共2000个文件以xml和txt为主附带py划分脚本、yaml配置及html图文教程整体大小约103.51MB。除数据外还附赠YOLO环境搭建Windows/Linux、训练案例教程以及数据集划分脚本可自行划分训练集、验证集和测试集适合快速上手实战。目前已有358人学习下载配套详情与更多资源可在作者博客查看。1. 红花目标检测数据集1000张真实图片与三格式标签省掉标注和格式转换两件最磨人的事搞目标检测的人最清楚选数据集和标注标签花的时间往往比调模型还长。我最近拆的就是一份YOLO红花目标检测数据集1000张真实场景的红花图片VOC、COCO、YOLO三种格式标签一次给齐还附带三个划分脚本和Linux/Windows双平台训练教程。对刚入门目标检测、或者正在做课程设计和毕设的人来说这份资源把数据准备、格式转换、环境搭建和训练启动四件最磨人的事打包成一条能直接跑通的链路。做农业视觉、花卉识别、细粒度分类相关项目的会特别有获得感。2. 三种标签格式选型VOC(xml)、COCO(json)、YOLO(txt)的结构差异与使用边界2.1 解压后先看目录结构压缩包里到底有什么拿到压缩包不要急着解压就开跑先用一条命令把目录层级打出来看清这套资源的组成。我从头到尾翻了一遍压缩包内部结构大致是训练集、验证集、测试集划分脚本训练集、验证集划分脚本split_train_val生成ImageSets下txt文件划分脚本加上train_list.txt和四份HTML教程环境搭建Linux版、环境搭建Windows版、训练教程Linux版、训练教程Windows版另外就是1000张图片对应VOC、COCO、YOLO三种格式的标签目录。find . -maxdepth 2 -type f \( -name *.py -o -name *.html -o -name *.txt \) | sort这条命令把脚本、教程文档和数据清单一次性列出来。maxdepth限制在2层是为了不看标签子目录里的上千个xml文件否则输出会被刷屏。train_list.txt是数据清单做法是先打开它看文件名规律再拿图片目录里的文件名对比确认图片和标签是否一一对应。这里有个习惯值得养成任何数据集到手先跑文件名对齐检查后面训练报错能少一半。2.2 VOC、COCO、YOLO三种标注格式字段、坐标系与典型适用框架三种格式并存是这个数据集最大的价值点。VOC格式是xml文件标注框用绝对像素坐标坐标原点在图片左上角COCO格式是json文件用category_id关联类别bbox是[x, y, width, height]绝对像素表示YOLO格式是txt文件每行一个目标第一列是类别索引后面四列是归一化后的中心点x、中心点y、宽度w、高度h。把这三种格式的差异用一张表说清楚格式文件类型坐标表示类别写法典型适用框架VOCxml绝对像素xmin/ymin/xmax/ymax英文类名如red_flowerFaster R-CNN、SSD、老版YOLOCOCOjson绝对像素bbox为[x,y,w,h]category_id数字索引Detectron2、MMDetectionYOLOtxt归一化cx/cy/w/h在0~1之间类别索引从0开始YOLOv5、YOLOv8、YOLOv9看一个具体目标在三种格式里的差异最直观。一个红花框在VOC里是绝对坐标在COCO里多一个category_id映射表在YOLO里直接变成四行归一化浮点数annotation filename00123.jpg/filename size width1920/width height1080/height /size object namered_flower/name bndbox xmin412/xmin ymin233/ymin xmax689/xmax ymax517/ymax /bndbox /object /annotation{ images: [{id: 1, file_name: 00123.jpg, width: 1920, height: 1080}], categories: [{id: 0, name: red_flower}], annotations: [{id: 1, image_id: 1, category_id: 0, bbox: [412, 233, 277, 284]}] }0 0.2867 0.3472 0.1443 0.2630xml和json是给人看的txt是给YOLO训练循环直接吃的。txt文件里第一列的0就是类别索引训练时data.yaml里的names列表顺序必须和这个索引对齐索引写错了模型也能训练但预测出来的类别完全错位。COCO的category_id通常从1开始YOLO的class从0开始做格式转换时如果直接抄代码没做减一处理就会翻车。常见的格式转换做法是把VOC当成中转格式xml转txt用脚本解析bndbox然后做归一化xml转json则要额外维护category到id的映射表。这套数据集三种格式都给了跨框架复用时不需要重新标注这是它比只有单一格式的数据集实在的地方。3. 划分脚本实战把1000张红花图拆成训练、验证、测试三份的完整流程3.1 训练集、验证集划分脚本参数含义与复制逻辑第一个划分脚本解决的是最基础的场景只需要训练集和验证集两份数据。脚本逻辑是遍历原图目录按随机种子打乱顺序按比例拆成两个集合然后把图片和对应标签成对复制到新文件夹。下面是我按照这套资源里脚本的命名和用途整理的等价写法import os import shutil import random from pathlib import Path # 参数区按实际目录改 src_img_dir images # 原图目录 src_label_dir labels # YOLO标签目录txt格式 target_root split_data # 输出根目录 val_ratio 0.2 # 验证集比例 seed 42 # 随机种子固定后结果可复现 random.seed(seed) img_files [f for f in os.listdir(src_img_dir) if f.lower().endswith((.jpg, .jpeg, .png))] random.shuffle(img_files) val_count int(len(img_files) * val_ratio) val_files set(img_files[:val_count]) train_files set(img_files[val_count:]) for split_name, file_set in [(train, train_files), (val, val_files)]: img_out Path(target_root) / split_name / images label_out Path(target_root) / split_name / labels img_out.mkdir(parentsTrue, exist_okTrue) label_out.mkdir(parentsTrue, exist_okTrue) for img in file_set: shutil.copy2(os.path.join(src_img_dir, img), img_out / img) base os.path.splitext(img)[0] src_label os.path.join(src_label_dir, base .txt) if os.path.exists(src_label): shutil.copy2(src_label, label_out / (base .txt)) else: print(f[warn] {img} 没有对应的 txt 标签检查标注是否漏标)这段代码的关键在最后复制环节图片和标签必须成对搬运。训练YOLO时最常见的报错就是图片在但标签丢失导致训练时某个batch没有监督信号。val_ratio0.2意味着1000张图里800张进train、200张进val如果样本总量少可以把比例改成0.1。seed固定为42之后每次运行结果一致这个习惯很重要否则调参时同一份数据每次划分都不同实验结果没法对比。3.2 训练集、验证集、测试集划分脚本三份拆分与比例校验第二个脚本比第一个多了一个test集合。测试集的作用是模型训练完成后做最终评估训练过程中不碰它。这里有个容易误解的点验证集要参与训练时的调参和早停判断测试集要留到最后才用。我之前见过有人把测试集和验证集混用模型在验证集上指标好看但泛化能力一测就露馅根子就在数据划分不规范。import os import shutil import random from pathlib import Path src_img_dir images src_label_dir labels target_root split_data train_ratio 0.7 val_ratio 0.2 test_ratio 0.1 seed 0 assert abs((train_ratio val_ratio test_ratio) - 1.0) 1e-6, 三个比例之和必须等于 1 img_files [f for f in os.listdir(src_img_dir) if f.lower().endswith((.jpg, .jpeg, .png))] random.seed(seed) random.shuffle(img_files) train_count int(len(img_files) * train_ratio) val_count int(len(img_files) * val_ratio) train_files set(img_files[:train_count]) val_files set(img_files[train_count:train_count val_count]) test_files set(img_files[train_count val_count:]) for split_name, file_set in [(train, train_files), (val, val_files), (test, test_files)]: img_out Path(target_root) / split_name / images label_out Path(target_root) / split_name / labels img_out.mkdir(parentsTrue, exist_okTrue) label_out.mkdir(parentsTrue, exist_okTrue) for img in file_set: shutil.copy2(os.path.join(src_img_dir, img), img_out / img) base os.path.splitext(img)[0] src_label os.path.join(src_label_dir, base .txt) if os.path.exists(src_label): shutil.copy2(src_label, label_out / (base .txt))我在其他项目里用过的默认配比是7:2:1但小数据集上8:1:1更稳。总样本量少时验证集太大训练集数量不够模型欠拟合验证集太小则早停判断波动大所以1000张图用7:2:1或者8:1:1都合理。脚本末尾的assert会强制三个比例之和等于1浮点误差直接截断处理。复制时用的是copy2保留文件时间戳如果调试过程中反复执行脚本新的分配结果不会因为旧文件残留而中断。提示脚本输出的是新文件夹不会覆盖原始图片和标签。这是数据划分的基本底线——原数据永远保留划分只产生副本。3.3 split_train_val生成ImageSets下txt对齐VOC训练入口第三份脚本解决的问题比较具体如果要把数据喂给VOC风格的训练链比如老版SSD或Darknet框架的YOLO它需要的是ImageSets/Main下的train.txt、val.txt、trainval.txt文件这些txt里存的是图片路径不含扩展名。YOLOv5和YOLOv8已经不走这套逻辑了但好多人下载这个数据集是课程设计要复现老框架所以这个脚本仍然有用。import os import random from pathlib import Path xml_dir Annotations # VOC 格式 xml 目录 image_dir JPEGImages # 原图目录 output_dir ImageSets/Main # 输出目录 trainval_ratio 0.8 # trainval 占全部样本比例 train_ratio_in_trainval 0.9 # trainval 中 train 的占比 os.makedirs(output_dir, exist_okTrue) xml_files [f for f in os.listdir(xml_dir) if f.endswith(.xml)] random.seed(0) random.shuffle(xml_files) trainval_count int(len(xml_files) * trainval_ratio) trainval xml_files[:trainval_count] test xml_files[trainval_count:] train_count int(len(trainval) * train_ratio_in_trainval) train trainval[:train_count] val trainval[train_count:] def write_txt(name, file_list): out_path os.path.join(output_dir, name .txt) with open(out_path, w) as f: for xml_file in file_list: base os.path.splitext(xml_file)[0] f.write(os.path.join(image_dir, base) \n) write_txt(trainval, trainval) write_txt(test, test) write_txt(train, train) write_txt(val, val)注意trainval并不是train加val之外的新集合它是train和val的并集老训练流程里常见的是用trainval.txt训练、test.txt测试。train_ratio_in_trainval0.9表示trainval里90%分给train10%分给val实际效果相当于总样本的72%训练、8%验证、20%测试。train_list.txt在这个场景里是辅助文件可以拿它和生成的train.txt做diff确认没有缺图。4. 环境搭建与训练流程从Ubuntu/Windows零基础到跑通第一个红花模型4.1 环境搭建显卡驱动、CUDA、PyTorch、ultralytics四层依赖顺序环境搭建是新手翻车重灾区本质问题是依赖顺序。常见的做法是先确认显卡驱动版本再装匹配的CUDA然后在虚拟环境里装PyTorch最后安装ultralytics。顺序反了会出现装了包但跑训练时提示CUDA不可用的情况。Linux版教程里走的是Ubuntu路线装完系统后第一步不是pip install而是先把驱动确认好# 1) 确认显卡驱动和 CUDA 版本驱动装好了才有后面的事 nvidia-smi # 2) 创建独立 conda 环境避免污染系统 Python conda create -n yolo python3.10 -y conda activate yolo # 3) 安装 PyTorch注意 index-url 要和本机 CUDA 版本匹配 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 4) 安装 ultralytics自带 YOLOv8 和 YOLO 系列训练入口 pip install ultralyticsnvidia-smi输出的CUDA Version是驱动支持的最高版本这里有个常见误解驱动支持的CUDA版本不等于需要安装的CUDA toolkit版本PyTorch的cu118对应的是CUDA 11.8只要驱动版本高于这个数字就能用。Windows版教程的操作路径一样只是命令从终端换到Anaconda Prompt里执行。我一般会用Python 3.10而不是最新版本因为ultralytics对老版本Python的兼容性更好且torch的预编译包覆盖最全。注意不要在系统全局Python里直接pip install torch。我见过很多人在Ubuntu自带的Python 3.8里装了一堆包最后torch版本和系统库冲突整个环境都废了。4.2 修改数据配置与训练入口把示例用例改成红花单一类别环境搭好后要改的是数据配置。YOLOv8的入口不是直接给图片路径而是给一个yaml文件声明训练集、验证集、类别数和类别名。这套数据集里原本是示例配置改成红花数据集的关键在于nc改成1、names改成对应名字path: D:/red_flower_yolo # 数据集根目录Linux 下改成 /home/user/red_flower_yolo train: train/images val: val/images test: test/images nc: 1 names: [red_flower]path字段是根目录train和val写相对路径ultralytics会自动拼接。如果数据划分用的是脚本输出后的目录路径别写错写成train/images/src这类嵌套路径是常见错误。nc代表类别数量这个数据集只有红花一个类所以是1。names列表的顺序就是txt标签里class id对应的顺序class 0对应red_flower。训练命令对应地要指定数据yaml路径、预训练权重和训练参数yolo detect train datadata.yaml modelyolov8n.pt epochs100 imgsz640 batch16model改成yolov8n.pt表示用nano版本做初始化比从零训练收敛快很多。epochs100对1000张图的目标检测任务够用如果显存不够就把batch从16降到8或者4同时观察loss曲线决定是否加epoch。imgsz640是输入分辨率红花这类目标如果原图里花占的面积很小可以改成960或1280代价是显存占用翻倍、训练时间变长。4.3 训练过程怎么看loss曲线、mAP指标与中断恢复训练启动后输出会写进runs/detect/train目录里面weights文件夹下的best.pt和last.pt是最关键的产出。best.pt是验证集上mAP最高的权重last.pt是最后一轮epoch的权重。我判断训练是否正常的习惯是看前几个epoch的box_loss和cls_loss是否在稳定下降如果loss在震荡上升基本可以确定是学习率太大或者数据存在问题。训练中途断掉不用从头再来ultralytics提供了恢复入口yolo detect train resumeTrue注意resume会尝试从runs/detect/train目录下的weights/last.pt和args.yaml自动拼接训练状态前提是训练中途没有修改过数据配置。如果改了nc或数据集路径resume大概率报错这时候只能老老实实重新训练。另外Windows下跑训练路径分隔符反斜杠可能引起解析问题我一般会在data.yaml里统一用正斜杠或者用绝对路径。5. 避坑手册标签路径、类别索引、显存溢出与划分脚本里的六个坑5.1 标签与路径问题No labels、类别索引错位训练启动时报“train: No labels found in .../train.cache”是最经典的新手错误。现象是训练直接中断提示train目录里没有标签。原因是txt标签文件和图片文件名没对齐常见于手动划分数据集时图片目录用的jpg扩展名标签目录里是JPG大写或者图片文件名带后缀而标签文件名少了一段。解决方法是写个脚本对比两边的文件名把缺失的标签列表打印出来import os img_dir train/images label_dir train/labels img_names {os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.lower().endswith((.jpg, .png))} label_names {os.path.splitext(f)[0] for f in os.listdir(label_dir) if f.endswith(.txt)} missing_label img_names - label_names missing_img label_names - img_names print(缺标签的图片:, len(missing_label), sorted(missing_label)[:10]) print(缺图片的标签:, len(missing_img), sorted(missing_img)[:10])第二个高频问题是类别索引错位。现象是模型训练完mAP正常但预测时输出类别名张冠李戴。原因是COCO转YOLO时category_id减一这一步做重复了。COCO的category_id通常从1开始计数YOLO的class id从0开始转换时必须统一把编号减1否则类别1在YOLO里会被当成类别0。在这套数据集里三种格式都给了我建议训练时只用YOLO格式的txt需要跨框架再用转换脚本生成避免在同一个工程里混用。5.2 训练与显存问题CUDA out of memory、验证集指标虚高训练中途报“CUDA out of memory”很常见。现象是跑到某几个epoch直接OOM中断。原因是batch_size和imgsz乘起来超过显存上限尤其是输入分辨率从640提到1280后显存占用变成原来的四倍。解决方法是先降batch_size到4再不行降imgsz到640。如果还想用高分辨率可以开启梯度累积等效增大batch但代码里要动训练循环新手不建议一上来就玩。还有一个容易骗过自己的坑训练完mAP挺高但实际部署到新图片上一测全是漏检。现象表现为验证集指标90%以上真实场景效果远差于预期。原因通常是数据划分泄漏划分脚本执行了两次某些图片同时进了train和val模型在验证集上见过答案。解决方法是检查划分后的两个目录里文件是否有交集train_set set(os.listdir(split_data/train/images)) val_set set(os.listdir(split_data/val/images)) intersection train_set val_set print(train和val重复图片数:, len(intersection))注意做数据划分时原图目录和标签目录要放在同一个根目录下一起复制不要先复制图片再复制标签。两次执行的间隔里如果源目录内容变了交集检测都救不回来。5.3 划分脚本与标注数据问题重复复制、坐标出界划分脚本自身也有坑。现象是脚本执行完发现train和val里有相同图片或者运行第二次后目录里文件越来越多。原因是脚本没有检查目标目录是否已存在同名文件而且复制逻辑没有做互斥判断。解决办法是生成文件后立刻跑上一节里的交集检查同时每次划分前清空输出目录import shutil from pathlib import Path target_root Path(split_data) if target_root.exists(): shutil.rmtree(target_root)标注层面的坑比较隐蔽。xml里的bndbox坐标超出图片边界现象是训练时loss正常但mAP偏低推理结果框偏移明显。原因是用labelimg标注时拖拽出界或者图片压缩后没有同步更新xml坐标。解决办法是对所有xml做一次边界裁剪把坐标收缩到[0, width]和[0, height]区间内。同理YOLO txt里如果出现大于1的归一化坐标也要重点排查。数据集本身用labelimg标注的质量不差但不代表每个框都百分百在界内批量过一遍才能放心训练。最后一个坑和数据集大小有关。1000张图在YOLOv8n上大概半小时能跑完但如果你换yolov8x还开512的batch显存直接爆掉。先跑nano版本验证全流程确认数据划分、标签格式和训练参数都没问题再上大模型这是我个人的固定顺序。6. 进阶验证用best.pt做批量推理并反查标注质量训练完后不要只看训练日志里的mAP我习惯做一步视觉反查。加载best.pt对验证集做批量推理把结果图保存下来逐张对比标注框和预测框是否一致。这一步能发现标注阶段遗留的漏标和错标还能反推数据划分是否合理。from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict( sourcesplit_data/val/images, # 换成你的验证集图片目录 conf0.25, saveTrue, save_txtTrue, projectinfer_out )推理结果会写到infer_out目录每张原图对应一个txt结果文件。我用这套方法检查的思路是先看置信度分布验证集200张图里如果绝大多数预测置信度在0.5以下说明标注质量或类别定义有问题再看预测框和标注框的IoE交集面积占真实框面积的比例如果某个真实框在大多图片上反复被漏检基本是标注框位置偏移。红花这类目标边缘细碎标注时容易出现框偏半个花身的情况肉眼单张看不出来批量比对就藏不住了。验证通过后整个数据集才算真正跑通。我拿到这类带划分脚本和教程的数据资源第一件事永远是核对图片数和标签数是否一致再随机抽20张看标注覆盖率确认无误才喂给模型。这个动作已经变成我对所有下载数据集的下意识检查项希望帮到你。本文还有配套的精品资源点击获取