
简介草莓成熟度目标检测数据集面向计算机视觉、智慧农业及自动化采摘等领域的开发者和研究者可直接用于YOLO全系列网络训练。数据已按YOLO格式整理包含训练集、验证集与测试集分别约1900张、100张和20张图像标注类别有成熟与未熟两个等级class文件内附有具体类别名称方便直接调用。资源图片涵盖温室栽培、不同品种与生长阶段等多样场景可提升模型在实际农业环境中的泛化能力。资源文件总数为2000个其中1999个txt文件是每张图像的标签说明1个Python脚本show.py能将检测框可视化到原图上便于快速核查标注质量、调试模型输出整个压缩包仅55.48MB轻量易传输。目前已有392人学习下载特别适合需要构建草莓成熟度识别方案、或希望用真实农业场景数据进行目标检测入门与进阶练习的学习者也可作为课题实验、竞赛备战的参考数据集。1. 目标检测数据集为什么会以草莓成熟度为题成熟度识别在水果分拣场景里是最容易翻车的一环。颜色接近的品种、光照不均的果面、遮挡严重的花果单靠传统的颜色阈值根本无法稳定分出“青果—转色—成熟—过熟”的边界。目标检测数据集以草莓成熟度为题意味着这套数据的核心不是单纯框出草莓在哪而是把成熟度作为类别标签放进检测任务里每个实例既要有位置框也要有明确的成熟阶段标签。超过2k张图片这个量级也很有意思它高于模型验证阶段的“随手跑跑”又远低于动辄几十万张的工业数据集恰好对应一个中小规模项目从标注到训练再到部署的完整闭环。这里推荐用 YOLO 系列来做落地。原因在于 YOLO 训练流程对标注文件格式要求简单每行一个实例社区资料密集虽然是“目标检测数据集”但最终形态几乎必然是一个 YOLO 格式的目录结构。2k 张图的规模也适合在单卡 GPU 上完成训练不需要分布式方案。文章的主要受众是两类人一类是算法工程师拿着这批数据想快速评估标签质量和训练基线另一类是农业信息化方向的技术人员需要理解成熟度标注怎么设计才不至于把模型练偏。下面所有操作都以这份数据集存在为前提但步骤和参数同样适用于自己标注的其他成熟度数据集。2. 标签格式与草莓成熟度类别体系的对应关系2.1 成熟度划分的类别数量决定标签文件的第一列一份目标检测数据集的标签文件第一列永远是类别 ID。对于草莓成熟度识别类别划分有几档常见做法二分类可采/不可采、三分类青/转色/红、四分类青/转色/红/过熟。这份数据集标注了超过2k张图片大概率采用三分类或四分类因为只分两类的数据集对算法工程师的参考价值很有限——现实分拣线更需要知道“什么时候摘”而不是“能不能摘”。标注类别的具体方式直接决定data.yaml的写法。以三分类为例YOLO 格式的data.yaml应该写成# data.yaml path: ./strawberry_dataset train: images/train val: images/val names: 0: unripe 1: turning 2: ripe这里把unripe放在 ID 0 是刻意为之数据集里任何未知背景都会被模型当作背景把最常见的负样本类放在靠前位置预热阶段收敛更稳。而names的排序要和标注文件里的整数 ID 严格对齐这个映射关系一旦错位训练出来的模型在推理时会输出张冠李戴的成熟度。提示如果标注工具LabelImg、X-AnyLabeling 或 Roboflow导出的类别顺序和这里不一致先在脚本里把类别 ID 做一次重映射不要在data.yaml里硬改顺序。2.2 标签文件内容与常见坐标陷阱YOLO 格式的标签文件是.txt文件名与图片名保持一致如IMG_2043.jpg对应IMG_2043.txt内容每行五个数值顺序是类别ID、归一化中心x、归一化中心y、归一化宽度、归一化高度。下面的代码可以快速体检一份标签文件是否合格# inspect_labels.py import os label_dir strawberry_dataset/labels/train bad_files [] for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue with open(os.path.join(label_dir, fname), r) as f: lines f.readlines() for idx, line in enumerate(lines): parts line.strip().split() if len(parts) ! 5: bad_files.append((fname, idx, 列数错误)) continue cls_id int(parts[0]) x, y, w, h map(float, parts[1:]) if cls_id not in (0, 1, 2): bad_files.append((fname, idx, f类别ID非法: {cls_id})) if not (0 x 1 and 0 y 1): bad_files.append((fname, idx, 中心点越界)) if not (0 w 1 and 0 h 1): bad_files.append((fname, idx, 宽高越界)) print(f检查 {len(os.listdir(label_dir))} 个标签文件) if bad_files: print(f发现 {len(bad_files)} 处问题, 前5个: {bad_files[:5]}) else: print(全部标签格式合法)脚本的核心检查点是归一化坐标是否落在 (0,1) 区间内。这个脚本检查出来问题后一个需要注意的坑是label 里 x、y 是中心点而非左上角很多从 COCO 格式转过来的数据集容易在这里栽跟头转格式时的坐标换算公式是x_center (x_min x_max) / 2 / img_width。3. 用 YOLOv8 在 2k 张草莓成熟度数据集上完成一次完整训练3.1 数据集目录结构与 train/val 划分标准拿到数据集后第一步不是直接训练而是把目录结构整理到 YOLOv8 认识的形态。标准结构如下strawberry_dataset/ ├── data.yaml ├── images/ │ ├── train/ # ~1600张 │ └── val/ # ~400张 └── labels/ ├── train/ # 与images/train同名对应的txt └── val/ # 与images/val同名对应的txt训练集与验证集的比例建议 8:2 或 8.5:1.5。2k 张图片的规模下验证集至少留 300 张否则成熟度相邻类别的 mAP 波动会非常大不好判断模型是否真的收敛。划分时还要注意同一颗草莓的不同视角图片不能同时落在训练集和验证集里否则会造成数据泄漏mAP 虚高但到了真实分拣线上被打回原形。官方推荐用ultralytics库自带的划分逻辑但更可控的做法是写一个按“果实实例分组”的划分脚本# 在项目根目录执行, 先装依赖 pip install ultralytics scikit-learn # 划分数据集按图片文件名前缀分组 python - EOF import os, shutil from sklearn.model_selection import train_test_split img_dir strawberry_dataset/images/all imgs [f for f in os.listdir(img_dir) if f.endswith(.jpg)] train_imgs, val_imgs train_test_split(imgs, test_size0.2, random_state42) os.makedirs(strawberry_dataset/images/train, exist_okTrue) os.makedirs(strawberry_dataset/images/val, exist_okTrue) os.makedirs(strawberry_dataset/labels/train, exist_okTrue) os.makedirs(strawberry_dataset/labels/val, exist_okTrue) for split, fnames in [(train, train_imgs), (val, val_imgs)]: for fname in fnames: stem os.path.splitext(fname)[0] shutil.copy(os.path.join(img_dir, fname), fstrawberry_dataset/images/{split}/{fname}) lbl fstrawberry_dataset/labels/all/{stem}.txt if os.path.exists(lbl): shutil.copy(lbl, fstrawberry_dataset/labels/{split}/{stem}.txt) else: print(f警告: {stem} 缺少标签文件) print(f训练集 {len(train_imgs)} 张, 验证集 {len(val_imgs)} 张) EOF分组划分时不要只按文件名顺序切一刀要保证成熟度类别在训练集和验证集中的分布比例一致否则会出现“训练集全是青果、验证集全是熟果”的极端情况mAP 看起来还行但实际检测不可用。划分后可以打印每个类别的数量分布来复核。3.2 yolo 目标检测流程中的关键训练参数设置YOLOv8 训练命令是 yolo 目标检测流程里最常见的执行入口。针对 2k 张草莓图imgsz640是默认值不需要为了“看得更细”调到 1280因为草莓成熟度的识别主要依赖颜色和表面纹理分布不是依赖小目标的细节像素——调大分辨率只会让小 GPU 的显存爆炸收益微乎其微。# 单卡训练, 以 yolov8s 为预训练权重 yolo train \ modelyolov8s.pt \ datastrawberry_dataset/data.yaml \ epochs100 \ imgsz640 \ batch16 \ patience15 \ projectruns/strawberry \ namematurity_v1 \ workers4参数说明modelyolov8s.pt从 COCO 预训练的 small 版本开始训练迁移学习能大幅缩短收敛时间比yolov8n精度高比yolov8m训练快是 2k 数据量级下性价比较高的选择patience15验证集 loss 连续 15 个 epoch 不下降就提前停止。草莓成熟度数据集类别之间差异相对明显通常 60 个 epoch 左右就能收敛这个值可以有效防止过拟合workers4数据加载进程数Windows 上如果报错可改为 0Linux 上保持 4 能明显提升 GPU 利用率训练过程中重点关注终端输出的mAP50-95和mAP50两个指标。对成熟度识别来说mAP50的意义远大于mAP50-95——因为草莓果实不算小目标定位精度不需要像素级苛刻成熟度判断的核心是框住果实、再判类别。如果mAP50能到 0.9 以上而mAP50-95只有 0.6这是正常的不必焦虑。3.3 训练完成后推理验证最小命令训练结束后的推理命令同样用 yolo 入口指向验证集图片输出带成熟度标签的标注图# 用最优权重对验证集推理并保存可视化结果 yolo predict \ modelruns/strawberry/maturity_v1/weights/best.pt \ sourcestrawberry_dataset/images/val \ saveTrue \ conf0.25 \ projectruns/strawberry_predict \ nameval_pred其中conf0.25表示置信度阈值设为 0.25低于这个值的检测框会被丢弃。成熟度识别场景下建议把阈值设置在 0.2~0.3 之间——草莓转色阶段的果实颜色介于青红之间模型容易给出相对较低的置信度把阈值设太高会把“转色”这一类几乎全部滤掉直接导致成熟度分布统计失真。预测结果保存在runs/strawberry_predict/val_pred/下可以直接用图片查看器浏览肉眼快速检查边界情况。4. 成熟度识别比普通目标检测多出来的三类决策逻辑4.1 类别定义的连续性与相邻类别的边界处理普通目标检测的类别之间通常是离散的猫不是狗车不是人但草莓成熟度是连续变化的过程——青果和转色之间、转色和成熟之间没有一条干净的分界线。这是草莓成熟度目标检测数据集与通用目标检测数据集最本质的区别。处理这个问题的推荐做法是训练时引入“软边界”策略在标注转色阶段时只把颜色明显处于中间态的草莓标为 turning把稍有泛红但整体仍以青绿色为主的标为 unripe把九成熟以上但还没有完全变红的标为 ripe——宁可在边界处“错标”到相邻类别也尽量不要引入一个模糊的“半转色”类别。四分类或五分类的标签体系看着更精细但对于 2k 张图的数据集样本被稀释后每个类别的特征都学不充分边界反而更混乱。一个直接的验证方法是训练后查看混淆矩阵。YOLOv8 训练会在runs/strawberry/maturity_v1/confusion_matrix.png生成混淆矩阵图重点观察unripe与turning、turning与ripe这两组相邻类的互混比例。如果互混超过 20%优先检查标注是否存在系统性偏差用下面代码统计类别分布# count_class_distribution.py import glob from collections import Counter cnt Counter() for lbl_file in glob.glob(strawberry_dataset/labels/train/*.txt): with open(lbl_file) as f: for line in f: cls_id int(line.split()[0]) cnt[cls_id] 1 total sum(cnt.values()) for cls_id in range(3): print(f类别 {cls_id} 实例占比: {cnt[cls_id]/total:.2%})4.2 从“框住果实”到“匹配成熟度”的推理逻辑用训练好的权重做推理输出格式不止是画框。实际分拣场景中经常需要把同一画面里的多个草莓按成熟度分组计数。YOLOv8 的 Python API 可以拿到结构化结果# run_inference.py from ultralytics import YOLO model YOLO(runs/strawberry/maturity_v1/weights/best.pt) results model(test_images/row1.jpg, conf0.25) for r in results: boxes r.boxes cls_names [model.names[int(c)] for c in boxes.cls.tolist()] confs boxes.conf.tolist() counts {name: cls_names.count(name) for name in set(cls_names)} print(f检测框数量: {len(boxes)}) print(f成熟度分布: {counts}) for name, conf in zip(cls_names, confs): print(f - {name}, 置信度: {conf:.2f})这段代码的用途是直接对接后续的分析模块——根据counts里的分布可以决定是否触发采摘指令或者把turning比例过高作为“再等一天”的决策信号。成熟度识别的价值不止于检测本身而是为采摘决策提供量化输入这正是它区别于普通“找到目标”类数据集的落点。4.3 光照与拍摄角度对成熟度类别的干扰及应对草莓成熟度数据集的第二只拦路虎是光照。同一颗七成熟的草莓在强光直射下可能被标成 ripe在阴影里又会被标成 turning。数据集超过2k张图片时标注时往往没有对光照做分层处理容易让模型学到“亮即熟”这种错误的捷径。推荐引入一个简单的数据增强策略来压制这个问题——在训练配置里增加 HSV 扰动参数yolo train \ modelyolov8s.pt \ datastrawberry_dataset/data.yaml \ epochs100 \ imgsz640 \ batch16 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4 \ mosaic0.5 \ fliplr0.5这里的hsv_h0.015表示色相扰动幅度对颜色敏感的成熟度识别任务来说这个值要尽可能小0.01~0.02 为宜色相是定义草莓红绿边界的最关键维度扰动过大会直接破坏类别定义让模型在青果和熟果之间摇摆。hsv_s饱和度和hsv_v明度可以适当调大模拟不同光照条件下的果面表现这能显著提升模型在真实分拣线上的泛化能力。mosaic降到 0.5 而不是默认的 1.0是为了在 2k 张图的规模下保留更多原图中的真实背景上下文。5. 评估成熟度检测效果的几个针对性验证技巧5.1 预留一屏“标签噪声样本”专门观察边界表现通用目标检测的评估看的是整体 mAP但成熟度数据集必须单独观察边界样本。从验证集中挑出三类各 30 张典型图——包括明显青绿但带一丝红的、红色占 60% 左右仍在转色的、以及深红发暗的过熟果——把它们单独放到一个文件夹反复做推理测试。# 单独跑边界样本集 yolo predict \ modelruns/strawberry/maturity_v1/weights/best.pt \ sourceboundary_samples/ \ saveTrue \ conf0.2 \ projectruns/strawberry_predict \ nameboundary_check这类测试的判定标准只有一个是否稳定落在人工标注的相邻类别上。比如一张人工标为 turning 的草莓模型输出 ripe 可以接受但如果输出 unripe说明模型的类别边界整体偏离需要回看训练集的标注一致性而不是盲目调阈值。提示YOLOv8 的 predict 模式默认输出的是带标签的可视化图里面每颗草莓框上都标了类别名和置信度比直接看数字指标更直观。5.2 用混淆矩阵和类别 mAP 验证成熟度分类的可靠性训练结束后在runs/strawberry/maturity_v1/目录下会生成三份关键文件——confusion_matrix.png、results.png、PR_curve.png。对成熟度数据集来说比起整体 mAP更值得打印的是每类详细指标# metrics_per_class.py from ultralytics import YOLO model YOLO(runs/strawberry/maturity_v1/weights/best.pt) metrics model.val(datastrawberry_dataset/data.yaml, splitval) for i, name in model.names.items(): cls_ap50 metrics.box.ap50[i] cls_ap metrics.box.ap[i] print(f{name:10s} AP50: {cls_ap50:.4f} AP50-95: {cls_ap:.4f})如果unripe的 AP50 明显低于ripe差距超过 0.1大概率是数据集中青果样本量偏少或者青果与叶片背景颜色接近导致的误检这时需要回到数据集层面补充青果样本而不是增加训练轮数。5.3 成熟度数据集常见的过拟合信号与对应调整2k 张规模的数据在训练 100 epoch 时极易出现过拟合最直接的信号是训练集 loss 持续下降而验证集 loss 在某个 epoch 后反弹。对应调整手段按优先级排列第一检查patience是否生效如果训练在 60 epoch 后就停止说明验证集已经连续 15 轮没有改善此时不必强迫它跑到 100 轮。第二给mosaic0.5的基础上额外加mixup0.2混合样本增强在颜色连续变化的任务上有奇效能模拟出不同成熟度果实相邻出现的真实场景。第三降低batch到 8 并对所有图片做一次居中裁剪减少模型对背景纹理的记忆。最后还要提一个容易被忽视的验证手段把best.pt在完全没有标签的新拍摄视频上跑一次连续帧推理观察同一颗草莓在视角变化时成熟度类别是否跳变。如果频繁跳变说明模型的类别边界对观察角度敏感此时最有效的方法不是调模型而是在标注阶段把多角度样本覆盖进去——这正是超过2k张图片的数据集值得投入的延伸价值所在。本文还有配套的精品资源点击获取