简介:面向红花目标检测任务的YOLO系列模型训练,这份数据集包提供了1000张真实场景的高质量红花图片,均由LabelImg标注,框体精确、质量可靠。数据涵盖不同光照、角度与生长阶段,场景丰富,有助于提升模型泛化能力。资源内同时给出VOC、COCO、YOLO三种格式标签,分文件夹存放,可直接接入主流YOLO训练流程,省去格式转换步骤。包内还附带Linux与Windows两种系统的YOLO环境搭建教程、基于案例修改的训练教程,以及训练集/验证集/测试集划分脚本,用户可按需求自行划分数据,适合课程设计、毕业设计及科研复现。资源共2000个文件,以xml与txt标签文件为主,另有6个HTML教程页、3个Python脚本和1个YAML配置文件,压缩包大小约103.51MB。目前已有360人学习下载,适合目标检测入门及进阶用户快速上手。
1. 红花目标检测数据集:这份1000张RAR里到底有什么,值得花时间吗
做红花目标检测,最耗时间的往往不是调网络结构,而是把数据“喂”对。拍1000张红花图可能只要小半天,但标注、格式整理、训练集切分、坐标归一化,随便一个坑都能让你返工一整周。
这份标题里的RAR,把红花检测最常缺的几样东西都补上了:1000张红花图片,VOC、COCO、YOLO 三种标签,配套的划分脚本和训练教程。拿到手后真正要做的只剩校验数据、跑切分转换、再启动训练。下面按一线落地顺序来拆:先讲三种格式的对应关系,再给直接能改的划分与转换脚本,最后落在训练、避坑和验证上。
适合刚想用YOLO系列做作物检测、又不想在数据准备上反复返工的人。读完你能判断这份数据值不值得投时间,也知道第一步该做什么。
2. 红花三种标签格式:VOC、COCO、YOLO 各自如何描述目标框,选型时看什么
三种格式不是三套不同的标注内容,而是同一个矩形框的三种表达方式。VOC 格式来自早期目标检测竞赛,COCO 格式来自另一套评测体系,YOLO 格式则是训练框架直接读取的结果。如果你觉得“反正都是框,格式无所谓”,就很容易在训练启动后才发现:标签文件读取为空、坐标偏移出画面、类别编号错位。先用对格式,再谈训练。
2.1 同一朵红花在三种格式里的表示
VOC 是一张图对应一个 XML 文件,文件名和图片名相同,适合人肉检查。假设一张图片叫 red_flower_001.jpg,它的 VOC 标注大致长这样:
<annotation> <filename>red_flower_001.jpg</filename> <size> <width>1920</width> <height>1080</height> </size> <object> <name>red_flower</name> <bndbox> <xmin>624</xmin> <ymin>417</ymin> <xmax>743</xmax> <ymax>551</ymax> </bndbox> </object> </annotation>这段 XML 表达的信息是:图中有一朵红花,目标框左上角在 (624, 417),右下角在 (743, 551)。size 里的宽高是图片原始尺寸,转换格式时要用它做分母,不能用训练时的目标尺寸。一个 XML 里可以写多个 object,代表一张图里有多个红花目标。
COCO 不按图片拆文件,而是把所有图片记录和所有目标框放进同一个 JSON,用 ID 关联。同样一朵红花,在 COCO 里是这样的:
{ "images": [ {"id": 1, "file_name": "red_flower_001.jpg", "width": 1920, "height": 1080} ], "annotations": [ {"id": 1, "image_id": 1, "category_id": 1, "bbox": [624, 417, 119, 134], "area": 15946, "iscrowd": 0} ], "categories": [ {"id": 1, "name": "red_flower"} ] }COCO 同样使用绝对像素坐标,但格式是[x, y, width, height],也就是左上角坐标加框的宽高,而不是右下角。area 是目标区域面积,矩形框可以直接写宽乘高;评测工具有时会比较严格,转格式时尽量保留原始值。注意这里的 x、y 是左上角,不是中心点。
YOLO 训练标签是最简短的一种:每张图一个 txt,每一行代表一个目标框。五个数字分别是类别编号、框中心 x、框中心 y、框宽、框高,后四个都要除以图片宽或高做归一化。
0 0.355989 0.448148 0.061979 0.120370这一行就是把 VOC 例子里的框换算后的结果:0.355989 = (624 + 743) / 2 / 1920,0.448148 = (417 + 551) / 2 / 1080,0.061979 = (743 - 624) / 1920,0.120370 = (551 - 417) / 1080。
三种格式的差异可以归纳成一张表:
| 格式 | 组织方式 | 坐标体系 | 一个目标框的字段 | 典型适用 |
|---|---|---|---|---|
| VOC | XML 按图片 | 绝对像素,左上角 + 右下角 | xmin, ymin, xmax, ymax | 早期框架、自定义数据 |
| COCO | 一个 JSON | 绝对像素,左上角 + 宽高 | bbox: [x, y, width, height] | 通用评测、跨框架数据 |
| YOLO | TXT 按图片 | 归一化,中心点 + 宽高 | class, x_center, y_center, width, height | YOLO 系列直接训练 |
记住三种格式相互转换时最危险的地方就是坐标系混用:VOC 用右下角,COCO 用宽高,YOLO 用归一化中心。转换脚本写错一个位置,框就会平移半个图。
2.2 训练框架读什么就用什么:别被“格式多”带偏
标题里三种都给,不等于三种都要用。选型原则很简单:训练框架读什么,你就喂什么。当前主流 YOLO 系列工具包默认读 YOLO 格式 txt,所以我一般把 YOLO 作为工作格式,VOC 和 COCO 作为存档格式。需要换框架时,从存档格式重新转换,而不是去改 txt;需要对标 COCO 评测指标时,直接使用原来的 COCO JSON。
还要注意两个共性坑。第一,类别编号从 0 开始;第二,names列表的顺序就是编号的索引。假设只有一个红花类,那类别编号一定是 0,data.yaml 里的 names 就只写['red_flower']。如果哪一天在原数据里加了叶子类,所有已转换 txt 里的编号都会变,必须重新生成标签,不能手工去改。
2.3 解压后的三步核对:数量、类别、画框抽查
拿到 RAR 后不要急着训练,先花 10 分钟核对。常见目录组织如下,但不同打包者可能有差异,以实际解压结果为准:
flower_dataset/ ├── images/ # 1000张图片 ├── VOC/ # 与图片同名的xml ├── COCO/ # 一个json ├── YOLO/ # 与图片同名的txt ├── split_data.py # 划分脚本 └── train_guide.md # 训练教程核对三步。第一,图片数量和标签数量是否一致。在命令行里分别统计 images 目录和 YOLO 目录的文件数,数量对不上就先查缺哪张。第二,类别是否只有一种。读一遍标签文件里的第一列,应该全是 0;如果出现 1,原始标签可能还有第二个类,训练时别把 nc 写成 1。第三,抽 10 张图把框画出来。下面的脚本读 YOLO 标签,把归一化坐标换算回像素坐标画框:
import cv2, os img_path = "images/red_flower_001.jpg" txt_path = "YOLO/red_flower_001.txt" img = cv2.imread(img_path) h, w = img.shape[:2] with open(txt_path) as f: for line in f: c, xc, yc, bw, bh = map(float, line.split()) x1 = int((xc - bw / 2) * w) y1 = int((yc - bh / 2) * h) x2 = int((xc + bw / 2) * w) y2 = int((yc + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imwrite("check.jpg", img)脚本逻辑是把归一化中心点和宽高,通过图片实际尺寸换算回左上角和右下角像素坐标,再用画框函数标出来。如果框完全覆盖花朵,没有明显平移或超出边界,说明这份 YOLO 标签可用。如果多张图都偏在同一个方向,最可能是原始 VOC 的 size 字段和实际图片尺寸不一致,需要以实际图片重新计算坐标。
3. 划分与转换:把1000张红花图拆成训练/验证/测试集,并统一到YOLO格式
这一步的目标是把 1000 张红花图拆成训练、验证、测试三个集合,并得到一份干净的 YOLO 格式工作副本。标题里的划分脚本可以直接用,但我仍然建议把下面几个关键逻辑搞清楚。划分坑造成的指标虚高,比模型调参更隐蔽,常常让你误以为自己训练出了好模型。
3.1 划分脚本的关键逻辑:固定种子、不重叠、分层抽样
第一,随机种子必须固定。同一套数据跑出的随机序列不同,训练集和验证集的组成就不同;不固定种子,两次实验的 mAP 差异会超过模型本身改进带来的差异,所有实验都无法对比。第二,图片级不重叠。划分的粒度是图片名,而不是图片里的框;同一张图只允许出现在一个集合里,不允许一张图既是训练又是验证。第三,抽样尽量分层。1000 张红花图看似不多,但往往来自几个拍摄批次。如果连续拍摄的几十张图全进验证集,验证指标会高得离谱,因为你已经在训练集里“见过”同场景了。没有批次信息时,按文件名排序后间隔抽取,比直接取前 800 张安全得多。
3.2 一个可以直接跑的划分脚本
下面的脚本把图片和 YOLO 标签按 8:1:1 切到 train、val、test 三个目录,并生成对应的路径清单文件:
import os, random, shutil src_img = "images" # 原始图片目录 src_label = "YOLO" # 原始YOLO标签目录 train_dir, val_dir, test_dir = "train", "val", "test" ratios = [0.8, 0.1, 0.1] random.seed(2024) # 提取所有jpg图片的不带后缀文件名 names = [os.path.splitext(f)[0] for f in os.listdir(src_img) if f.lower().endswith(".jpg")] random.shuffle(names) n_train = int(len(names) * ratios[0]) n_val = int(len(names) * ratios[1]) split = { train_dir: names[:n_train], val_dir: names[n_train:n_train + n_val], test_dir: names[n_train + n_val:] } for out, items in split.items(): os.makedirs(os.path.join(out, "images"), exist_ok=True) os.makedirs(os.path.join(out, "labels"), exist_ok=True) for name in items: shutil.copy(os.path.join(src_img, name + ".jpg"), os.path.join(out, "images", name + ".jpg")) shutil.copy(os.path.join(src_label, name + ".txt"), os.path.join(out, "labels", name + ".txt")) with open(out + ".txt", "w") as f: f.writelines([f"{out}/images/{name}.jpg\n" for name in items])脚本做的事很直接:读 images 目录下的 jpg,提取文件名后随机打乱,按比例切成三段,再把图片和同名 txt 复制到 train、val、test 各自的 images/labels 目录,同时生成 train.txt、val.txt、test.txt。这些 txt 文件的作用是给训练框架提供图片路径清单。
参数说明:src_img和src_label必须改成你解压后的实际路径;ratios加起来等于 1,不需要测试集时可以设[0.9, 0.1, 0]。random.seed的值可以换,但固定后每次结果一致。如果图片里.jpg和.png混用,上面脚本会漏掉 png,建议先打印len(names)和目录文件数核对。另外生成的 train.txt 里是相对路径,训练脚本若从别处启动,建议改成绝对路径,或统一用 data.yaml 管理路径。
注意:如果标签目录里有少数图片没有任何目标,也就是空 txt,训练框架通常也会报错。划分后顺手扫描一遍,把空 txt 对应的图片一起移出数据集,比训练时逐个排查快得多。
3.3 VOC/COCO 转 YOLO:归一化坐标脚本
标题里既然给了 VOC、COCO、YOLO 三种标签,最省事的方式是直接确认 YOLO 目录是否完整;如果手头只有 VOC 或 COCO,则用转换脚本生成 YOLO 标签。转换公式只有一个,以 VOC 为例:
import os, glob import xml.etree.ElementTree as ET cls_map = {"red_flower": 0} src_xml = "VOC" dst_txt = "YOLO" os.makedirs(dst_txt, exist_ok=True) for xml_path in glob.glob(os.path.join(src_xml, "*.xml")): tree = ET.parse(xml_path) root = tree.getroot() w = int(root.find("size/width").text) h = int(root.find("size/height").text) base = os.path.splitext(os.path.basename(xml_path))[0] lines = [] for obj in root.findall("object"): name = obj.find("name").text if name not in cls_map: continue # 跳过未映射类别 box = obj.find("bndbox") xmin = float(box.find("xmin").text) ymin = float(box.find("ymin").text) xmax = float(box.find("xmax").text) ymax = float(box.find("ymax").text) xc = (xmin + xmax) / 2.0 / w yc = (ymin + ymax) / 2.0 / h bw = (xmax - xmin) / w bh = (ymax - ymin) / h lines.append(f"{cls_map[name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}") with open(os.path.join(dst_txt, base + ".txt"), "w") as f: f.write("\n".join(lines))脚本先解析每个 XML 里的图片尺寸,再遍历所有 object,把左上角和右下角坐标按公式归一化。cls_map定义了类别名到编号的映射,如果数据集有多个类,要先把映射补齐再跑。COCO 转 YOLO 同理,只是把 bbox 的[x, y, width, height]换算成xc = (x + width / 2) / 图片宽、yc = (y + height / 2) / 图片高、bw = width / 图片宽、bh = height / 图片高,其余逻辑相同。
这里有两个参数细节必须强调。一是坐标字段要强转 float,否则 Python 整数除法会把小于 1 的结果直接变成 0,最终所有框都缩在图片左上角。二是除以的必须是原始图片宽高,不是训练时的输入尺寸;一旦写成训练尺寸,框的比例会被二次压缩。
3.4 转换后的标签校验:框画到图上,数一数行数
转换完别直接训练。先做一个全量校对,统计每个 XML 的 bndbox 数量和对应 txt 行数:
for f in VOC/*.xml; do n=$(grep -c '<bndbox>' "$f") t="YOLO/$(basename "$f" .xml).txt" m=$(wc -l < "$t") echo "$f $n $m" done输出中第二列和第三列应当相等。不相等的一行重点看:XML 里有没有空白 object、转换脚本是否跳过了未映射类别、文件名对不对得上。然后随机抽 20 张,用 2.3 的画框脚本再画一次。如果画出的框偏移、溢出图片,优先怀疑 XML 的 size 字段与实际图片不一致,或者转换公式用错了坐标系。
4. 红花目标检测训练教程与避坑排查:环境、启动命令、五个高频翻车点
现在数据已经是干净的 YOLO 格式,可以进入训练环节。标题里的训练教程通常会给一套完整命令,我更想强调那些“参数看起来无关、实际决定成败”的配置。第一次做红花检测,把环境、配置、参数这三件事做对,训练成功率会高很多。
4.1 环境配置与 data.yaml 写法
先把数据目录整理成框架最容易识别的结构。用 3.2 的划分脚本之后,目录会是:
data/ ├── train/ │ ├── images/ │ └── labels/ ├── val/ │ ├── images/ │ └── labels/ └── data.yamldata.yaml 是训练时最关键的配置文件:
path: data train: train/images val: val/images test: test/images nc: 1 names: ['red_flower']path填数据总目录,train和val填相对该目录的图片路径,labels 目录不需要写,框架默认在图片同级找 labels。nc是类别数,names顺序必须和 YOLO 标签里的编号一致,这里的names[0]对应编号 0。
环境准备按你选定的 YOLO 工具包说明来。我一般先建独立虚拟环境,再装依赖,最简流程是:
python -m venv venv source venv/bin/activate pip install -r requirements.txt不同 YOLO 版本的依赖来源不同,以训练教程为准。GPU 环境记得提前装好驱动和对应版本的深度学习框架;显存不够不是非得换卡,把 batch 降到 8 也能跑通,只是慢一点。
4.2 启动训练的最小命令
启动训练的命令以 train.py 为例:
python train.py --data data/data.yaml --weights pretrained.pt --img 640 --batch 16 --epochs 100--data使用上面的 data.yaml;--weights接一个预训练模型文件。红花这种植物目标,和预训练模型里的通用物体特征差异不算大,迁移后收敛很快;--img是训练输入边长,--batch是批大小,--epochs是最大训练轮数。训练完会生成 best.pt 和 last.pt,best 是验证集指标最好的那一轮,后续推理和导出都优先用 best.pt。
提示:第一次启动训练时,先确认日志里打印的训练样本数和验证样本数接近 9:1。如果验证集数量只有几十张甚至为 0,别急着调参,回第 3 章检查划分脚本。
4.3 三个必调参数:epochs、imgsz、batch
| 参数 | 作用 | 红花数据建议值 | 设错的后果 |
|---|---|---|---|
| epochs | 最大训练轮数 | 100~200 | 太少欠拟合,太多过拟合 |
| img | 训练输入边长 | 640 或 512 | 太大显存爆,太小漏掉小花 |
| batch | 每次迭代图片数 | 16 或 32 | 太大 OOM,太小收敛慢且 loss 震荡 |
红花目标小、分布密,输入尺寸比常规大目标更关键。640 跑不动就降到 512;降到 416 以后,一朵直径只有二三十像素的红花基本被背景噪声覆盖,再调模型也没用。batch 的调整顺序是:优先保证 batch 不小于 8,然后通过控制 img 尺寸把训练跑起来。epochs 先给 100,配合早停,效果不够再继续加;训练时观察 val_loss,连续多轮不下降会自动停止,所以不用一直守在电脑前。
4.4 五个高频翻车点与止损方案
现象:训练正常跑完,但推理时大面积漏检。 原因:data.yaml 的 names 顺序和转换脚本的 cls_map 不一致,或者类别编号从 1 开始,导致模型学到的编号和推理时映射的类别对不上。 解决:打开 data.yaml,核对 nc 和 names;再回 3.3 检查 cls_map。单类红花应该是
{"red_flower": 0},data.yaml 里 names 只能有一项。现象:训练刚开始 loss 变成 nan,或者 loss 特别大。 原因:标签坐标没有归一化,某个 txt 为空,或者标签里有负数坐标。 解决:写一个脚本扫描所有 txt,检查每行五个数字是否都在合法范围,尤其是
0 <= x_center <= 1、0 <= width <= 1。空 txt 对应的图片直接移出数据集,不要保留。现象:验证集 mAP 很高,测试集一塌糊涂。 原因:数据划分时没有固定随机种子,或者同场景连续帧被同时分到训练集和验证集,形成了数据泄露。 解决:重新按文件名随机打散后划分;如果有拍摄批次信息,按批次分层抽样,保证同一个批次的图片只出现在一个集合里。
现象:训练报显存不足。 原因:batch 32 加 img 640,在普通显卡上很容易超显存。 解决:先 batch 8、img 512 跑通,确认数据和配置没问题后再逐步调大。不要一次性全开,翻车概率很高。
现象:框位置基本正确,但类别显示成 class-0 之外的编号。 原因:推理脚本没有加载 data.yaml 的 names,或加载的 names 顺序和训练时不一致。 解决:推理时显式传入
--data data/data.yaml,让模型按训练时的类别表输出名称。
5. 训练后的验证与迭代:mAP 怎么看、可视化推理、下一轮数据怎么补
5.1 mAP 的两级指标怎么读
训练日志里最常看的是 mAP@0.5 和 mAP@0.5:0.95。前者把置信度阈值设在 0.5,衡量粗定位好不好;后者在多个阈值下求平均,对框的精细程度更敏感。红花数据如果 mAP@0.5 高但 0.95 低,说明框大体有、边缘不齐,优先提高输入分辨率,而不是加模型复杂度。单类红花验证集 mAP@0.5 通常能到 0.85 以上,mAP@0.5:0.95 到 0.6 左右,已经可以跑一轮实景测试。
5.2 可视化推理:不要只看 loss
loss 降到很低不代表模型能用。把一批测试图片送进推理脚本,命令类似:
python detect.py --weights runs/.../best.pt --source data/test/images --data data/data.yaml --save-txt看结果时记录两类现象:漏检的小花和误检的叶片。漏检多发生在远景密集株,误检多发生在红花盛开且颜色和背景接近时。把这些图按场景归类,就是下一轮迭代的最重要输入。
5.3 下一轮数据补什么最有效
第一轮训练后,我不急着改网络参数,而是把置信度低于 0.5 但实际是花的图挑出来,看哪些场景占多数:逆光、植株重叠、还是极小花。然后针对性补 50 到 100 张,重新跑划分和训练。因为你手里已经有 VOC、COCO、YOLO 三种标签和划分脚本,补标数据后重新转格式的成本很低;格式转换和划分脚本就是你的后悔药,改错了重新跑一遍也不会污染原始标注。这个“训练-挑错-补数据-再训练”的循环,比反复调学习率更能解决红花检测的大多数问题。
我自己的习惯是每轮训练固定同一个随机种子,保证每次对比只反映数据或参数的变化;等这套流程稳定后,才把种子放开去看整体波动。希望帮到你。
本文还有配套的精品资源,点击获取