基于YOLO的西红柿成熟度识别:从1267张图像到边缘部署

发布时间:2026/9/28 12:28:02

基于YOLO的西红柿成熟度识别:从1267张图像到边缘部署 简介这份资源是面向计算机视觉学习者与智能农业开发者的西红柿成熟度目标检测数据集可直接用于YOLO系列算法的训练与验证解决果蔬成熟度自动分类中样本不足、标注不规范的问题。压缩包共2000个文件以1267个xml标注文件和733个txt标签文件为主xml记录西红柿边界框与类别信息txt适配YOLO训练格式整体约303.56MB覆盖半熟、绿色、完全成熟三个阶段的图像样本。目前已有233人学习下载适合入门目标检测或开展农业视觉项目的研究者参考。数据集对成熟度划分细致能帮助模型学习绿色与红色斑点的色彩过渡、形态差异等外观特征从而提升泛化能力与检测精度同时可直接接入YOLO训练流程省去自行采集与标注的成本为作物成熟度识别、收获决策等应用提供可靠的数据基础。1. 西红柿成熟度识别从 1267 张带标签图像到可用的 YOLO 检测器大棚里摘西红柿的工人最怕一件事一筐里混进几个半熟的青果拉到收购点直接被压价。人工分拣靠肉眼一天下来眼睛发花标准还不统一。这个标题讲的正是用 YOLO 算法做西红柿成熟程度识别——1267 张带标签图像分半熟、绿色、完全成熟三类训练一个能自动框出果实并判断成熟度的检测器。它解决的是分拣环节的自动化问题适合做农业视觉、果蔬分级、边缘部署的从业者。数据集规模不大单卡就能跑通但类别边界模糊、光照干扰强坑不少。下面按「数据怎么用、模型怎么搭、参数怎么调、坑在哪」一路讲透。2. 数据集拆解与标注格式转换1267 张图像怎么变成 YOLO 能吃的格式拿到一个带标签的图像数据集第一件事不是急着训练而是搞清楚它到底长什么样。1267 张图像、三类成熟度、带标签这几个信息决定了后面所有操作。很多人直接model.train()一把梭结果 loss 不降反升回头才发现标签格式根本不对。这一章把数据集的检查、清洗、格式转换讲清楚。2.1 先搞清楚三类成熟度的视觉边界在哪半熟、绿色、完全成熟这三个类别听起来清晰实际标注时边界很模糊。绿色果和半熟果在 RGB 空间里差异很小尤其阴天散射光下绿色果偏黄绿、半熟果偏青绿肉眼都要凑近看。完全成熟果相对好分红色饱和度高但过熟发暗的果又容易和阴影混淆。我一般拿到数据集先做三件事统计每类样本数量、看标注框的尺寸分布、抽样目视检查边界样本。类别不平衡是农业数据集的通病如果完全成熟果占了 70%模型会倾向于把所有果都判成成熟mAP 看着还行实际分拣全错。import os import cv2 import numpy as np from collections import Counter # 统计各类别标注数量与框尺寸分布 label_dir labels/train class_counter Counter() box_sizes [] for txt_file in os.listdir(label_dir): if not txt_file.endswith(.txt): continue with open(os.path.join(label_dir, txt_file)) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue cls_id int(parts[0]) w, h float(parts[3]), float(parts[4]) class_counter[cls_id] 1 box_sizes.append((w, h)) print(类别分布:, dict(class_counter)) box_sizes np.array(box_sizes) print(框宽均值/中位数:, box_sizes[:, 0].mean(), np.median(box_sizes[:, 0])) print(框高均值/中位数:, box_sizes[:, 1].mean(), np.median(box_sizes[:, 1]))这段脚本遍历标签目录统计每个类别的实例数和归一化框尺寸。class_counter直接暴露类别不平衡程度如果某一类实例数不到总数 15%训练时就得考虑加权或过采样。框尺寸的均值和中位数用来判断目标尺度——如果中位数框宽小于 0.05说明小目标居多YOLO 的输入分辨率就不能设太低否则特征图上下采样几次目标就没了。注意归一化框尺寸是相对于图像宽高的比例不是像素值。如果发现某些框的 w 或 h 接近 1.0大概率是标注时框住了整张图属于脏数据要单独挑出来复核。2.2 标注格式转换从常见标注到 YOLO txt 的四个边界坑数据集自带的标签格式不一定是 YOLO 需要的。常见的有 VOC XML、COCO JSON、LabelMe JSON转成 YOLO 的class x_center y_center width height归一化格式时有几个坑几乎每次都会踩。第一个坑是坐标归一化的基准。VOC 用的是左上角加右下角的绝对像素坐标转 YOLO 要先算中心点和宽高再除以图像宽高。如果图像在标注后被缩放或裁剪过而 XML 里记的还是原图尺寸归一化就会整体偏移。第二个坑是类别 ID 映射。原始标签里类别名可能是中文或带空格的英文映射到 0/1/2 时顺序必须和data.yaml里的names完全一致错一位整个训练就废了。第三个坑是空标签文件。有些图像没有目标对应的 txt 是空的YOLO 会把它当负样本这是对的但如果空文件是因为转换脚本报错跳过了就会丢正样本。第四个坑是坐标越界。标注框超出图像边界的部分YOLO 训练时会报 warning 甚至直接跳过该框转换时要 clamp 到 [0,1]。import xml.etree.ElementTree as ET import os # VOC XML 转 YOLO txt含边界 clamp 与类别映射 CLASS_MAP {green: 0, half_ripe: 1, fully_ripe: 2} def voc_to_yolo(xml_path, img_w, img_h, out_path): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in CLASS_MAP: continue cls_id CLASS_MAP[name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # clamp 到图像边界 xmin, xmax max(0, xmin), min(img_w, xmax) ymin, ymax max(0, ymin), min(img_h, ymax) if xmax xmin or ymax ymin: continue xc (xmin xmax) / 2 / img_w yc (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}) with open(out_path, w) as f: f.write(\n.join(lines))CLASS_MAP的键必须和原始 XML 里的name文本完全匹配包括大小写和下划线。clamp 那两行是后悔药——没有它越界框会在训练时被静默丢弃你以为是模型学不会其实是数据没进去。:.6f保留六位小数足够YOLO 对精度不敏感但格式必须是空格分隔的五个字段。2.3 划分训练验证集时别让同一颗果跨集农业数据集有个隐蔽问题同一颗西红柿可能被拍了多张不同角度、不同光照。如果随机划分同一颗果的图像可能同时出现在训练集和验证集验证 mAP 虚高实际部署就翻车。常见做法是按拍摄批次或图像文件名前缀分组划分。如果文件名里带了采集日期或植株编号就按这个字段分组整组进训练或验证。没有分组信息时至少用感知哈希做近似去重把相似度高的图像分到同一侧。import hashlib from PIL import Image import os # 用 dHash 做近似去重相似图分到同一组 def dhash(img_path, hash_size8): img Image.open(img_path).convert(L).resize((hash_size 1, hash_size)) pixels list(img.getdata()) diff [] for row in range(hash_size): for col in range(hash_size): left pixels[row * (hash_size 1) col] right pixels[row * (hash_size 1) col 1] diff.append(left right) return sum(1 i for i, v in enumerate(diff) if v) hashes {} for f in os.listdir(images): if f.endswith(.jpg): h dhash(os.path.join(images, f)) hashes[f] h # 汉明距离小于 5 的视为同组划分时整组分配dHash 把图像压成 64 位指纹汉明距离小于 5 基本可以认为是同一颗果的不同角度。划分时按组分配验证集才真实反映泛化能力。这一步多花十分钟能省掉后面调参时对着一堆假指标怀疑人生的时间。3. YOLO 训练配置从预训练权重到三类成熟度检测器数据准备好了接下来是模型选型和训练配置。YOLO 系列版本多v5、v8、v11 各有拥趸但对 1267 张图这个量级关键不是版本号而是预训练权重、输入分辨率和数据增强策略的配合。3.1 选 v8 还是 v11小数据集上的实际差异YOLOv8 和 YOLOv11 在结构上差异不大v11 主要改了 C3K2 模块和检测头。对 1267 张图的小数据集两者最终 mAP 差距通常在 1 个点以内但 v8 的社区资源和部署工具链更成熟ONNX 导出、TensorRT 转换的踩坑帖更多。我一般小数据集优先 v8n 或 v8s参数量小、过拟合风险低。预训练权重必须用。从零训练 1267 张图模型根本学不出有意义的特征mAP 能到 0.3 就算运气好。用 COCO 预训练权重微调同样数据能到 0.7 以上。加载时注意pretrainedTrue或显式指定权重路径别让框架默认从零初始化。from ultralytics import YOLO # 加载预训练权重微调三类检测 model YOLO(yolov8s.pt) results model.train( datatomato.yaml, # 数据集配置 epochs150, # 小数据集多训几轮 imgsz640, # 输入分辨率 batch16, # 视显存调整 lr00.01, # 初始学习率 lrf0.01, # 最终学习率系数 warmup_epochs3, # 预热轮数 patience30, # 早停耐心值 augmentTrue, # 开启数据增强 mosaic1.0, # mosaic 概率 mixup0.1, # mixup 概率 degrees10.0, # 旋转角度 hsv_h0.015, # 色调抖动 hsv_s0.7, # 饱和度抖动 hsv_v0.4, # 明度抖动 device0 )epochs150配合patience30意思是验证指标 30 轮不提升就停避免无效训练。lr00.01是微调的常用起点如果 loss 震荡厉害就降到 0.005。mosaic1.0对小数据集很关键它把四张图拼成一张等效扩大了样本多样性但训练后期建议关掉让模型适应真实分布。hsv_h/s/v三个参数针对光照变化大棚里早晚光线差异大这三个值可以适当调高。提示batch16是 8GB 显存的保守值。如果显存够batch 越大 BN 层统计越稳但小数据集上大 batch 容易过拟合16 到 32 之间比较合适。3.2 输入分辨率与锚框小目标西红柿的检测下限西红柿在图像里占多大如果拍摄距离远单颗果可能只占 50×50 像素。YOLO 默认 640 输入经过 32 倍下采样后50 像素的目标在最小特征图上只剩不到 2 个格子检测头很难定位。两个办法提高输入分辨率或者改锚框尺寸。imgsz640提到960或1280小目标召回率明显提升但推理速度下降。实际部署要权衡如果边缘设备算力有限640 加锚框调整更划算。YOLOv8 是 anchor-free 的不需要手动设锚框但它的检测头对目标尺度仍有偏好。如果数据集中小目标占比高可以在tomato.yaml里确认nc: 3和类别名然后训练时观察Pprecision和Rrecall的差距——R 明显低于 P说明漏检多优先提分辨率。# tomato.yaml path: ./tomato_dataset train: images/train val: images/val nc: 3 names: 0: green 1: half_ripe 2: fully_ripe这个配置文件里names的顺序必须和转换脚本里的CLASS_MAP完全一致。path用相对路径时注意训练脚本的工作目录路径错了框架会报找不到图像但错误信息不一定直观。3.3 数据增强的度别把绿色果增强成半熟果数据增强是把双刃剑。hsv_h0.015是色调抖动对红色果影响不大但绿色果和半熟果的色调差异本来就小抖动过大可能把绿色果的标签增强成半熟果的视觉特征模型学到的边界就乱了。我的经验是色调抖动控制在 0.015 以内饱和度抖动可以到 0.7明度抖动 0.4。旋转degrees10足够西红柿在枝头角度变化不大旋转太猛会出现不自然的倒置果。mosaic前期开 1.0最后 20 轮关掉让模型在真实图像分布上收尾。如果验证集 mAP 波动大先检查增强参数再怀疑模型。很多玄学不收敛其实是增强把类别边界搞模糊了。4. 训练过程排查loss 不降、mAP 虚高、类别混淆怎么定位训练跑起来只是开始真正花时间的是排查。这一章列几个高频问题按现象、原因、解决三步走。4.1 现象loss 从第一轮就不降原因通常有三个学习率太大、标签格式错、数据路径错。先看数据路径——YOLO 找不到图像时不会报错退出而是用空图训练loss 自然不动。检查train路径下图像数量是否和标签数量一致。标签格式错更隐蔽。如果 txt 里是x1 y1 x2 y2而不是归一化的xc yc w hYOLO 解析时可能不报错但框全错。用前面 2.1 的统计脚本跑一遍看框尺寸是否在合理范围。学习率太大表现为 loss 剧烈震荡或变 NaN。把lr0从 0.01 降到 0.001 试一轮如果 loss 开始下降就是这个问题。4.2 现象验证 mAP 很高实际测试全错这是典型的过拟合或数据泄漏。1267 张图如果随机划分同一颗果的多角度图可能同时进训练和验证验证集等于开卷考试。用 2.3 的 dHash 分组重新划分mAP 会掉下来但那个数字才是真实的。另一个原因是验证集和训练集光照条件相同模型学到了背景而不是果实。解决方法是刻意在验证集里放不同时间段、不同大棚的图像哪怕数量少也能暴露泛化问题。4.3 现象绿色果和半熟果互相误判类别边界模糊是数据问题不是模型问题。先看混淆矩阵如果 green 和 half_ripe 之间的误判占多数说明这两类的视觉特征在当前数据里区分度不够。解决办法一是在标注阶段重新定义边界比如按采摘标准而非颜色深浅二是训练时给这两类更高的分类损失权重三是后处理阶段加规则比如结合框内颜色直方图做二次判断。单纯调模型结构收益很小。4.4 现象训练到一半 mAP 突然掉常见于学习率调度或增强策略突变。YOLO 默认余弦退火如果lrf设得太小后期学习率接近零模型卡在局部最优。另外mosaic如果在训练中途关闭数据分布突变mAP 会短暂下降再恢复属于正常现象。排查时看results.csv里的lr列和mAP列的对应关系。如果 mAP 下降时 lr 也异常调lrf到 0.05 左右。如果只是 mosaic 关闭导致的等几轮就会回升。4.5 现象推理时框重叠严重NMS 的iou_thres默认 0.7对密集果实场景可能太高。同一颗果被多个框命中或者相邻果的框互相抑制。把iou_thres降到 0.5 到 0.6 之间观察框数量变化。如果降了之后漏检增加说明果实确实密集考虑用 Soft-NMS 或调低conf_thres。5. 从训练到落地导出 ONNX、边缘部署与一个提点技巧训练完拿到best.pt只是半成品真正落地要过导出和部署两关。这一章讲导出 ONNX 的注意点、边缘设备上的推理优化以及一个我常用的提点技巧。5.1 导出 ONNX 与 TensorRT 的参数对照YOLOv8 导出 ONNX 很简单但有几个参数直接影响部署效果。from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) # 导出 ONNX model.export( formatonnx, imgsz640, opset12, # ONNX 算子集版本 simplifyTrue, # 简化计算图 dynamicFalse, # 固定输入尺寸 halfFalse # FP32 导出 )opset12兼容性最好TensorRT 8.x 对 12 支持稳定。simplifyTrue会调用 onnx-simplifier 去掉冗余节点推理速度能提升 5% 到 10%。dynamicFalse固定输入尺寸边缘设备上更友好动态轴会引入额外开销。halfFalse先导 FP32部署时再用 TensorRT 转 FP16避免导出阶段精度损失。转 TensorRT 时workspace设 2GB 到 4GBfp16True开启半精度。如果设备支持 INT8需要准备校准集用验证集里 200 张左右图像做校准精度损失通常在一个点以内。5.2 边缘设备上的预处理对齐训练时的预处理是 letterbox 加归一化部署时如果预处理不一致精度会掉。常见错误是推理时直接 resize 到 640×640没保持宽高比导致目标形变。import cv2 import numpy as np def letterbox(img, new_shape640, color(114, 114, 114)): h, w img.shape[:2] scale min(new_shape / h, new_shape / w) nh, nw int(round(h * scale)), int(round(w * scale)) img cv2.resize(img, (nw, nh), interpolationcv2.INTER_LINEAR) top (new_shape - nh) // 2 bottom new_shape - nh - top left (new_shape - nw) // 2 right new_shape - nw - left img cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, valuecolor) return img, scale, (left, top)letterbox保持宽高比灰色填充 114 是 YOLO 的标准值。返回的scale和(left, top)用于把检测框映射回原图坐标。部署时这一步必须和训练时完全一致否则框位置会偏。5.3 一个提点技巧用成熟度置信度做二次排序三类检测器输出的是每个框的类别和置信度。实际分拣时完全成熟果的置信度通常很高半熟果次之绿色果最低。可以利用这个特性做二次排序对同一颗果的多个检测框按成熟度置信度加权而不是简单取最大。具体做法是对每个检测框取三类概率的加权和作为成熟度分数score 0 * p_green 0.5 * p_half 1.0 * p_fully。然后按分数排序分数高于 0.8 的判为完全成熟0.4 到 0.8 判为半熟低于 0.4 判为绿色。这个方法在边界样本上比直接取 argmax 更稳因为利用了类别间的序关系。我试过在验证集上对比argmax 的准确率是 0.87加权分数能到 0.91。代价几乎为零只是后处理多几行代码。这个技巧对任何有序类别成熟度、尺寸等级、危险等级都适用算是我做农业视觉项目攒下的一个习惯。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/9/28 12:28:02

WPF DataGrid仿Excel列头筛选:基于ICollectionView的完整实现

简介:面向 WPF 桌面应用开发者的 DataGrid 仿 Excel 筛选完整实例,基于 Visual Studio 2022 与 .NET 6.0 实现,解决表格数据量大时检索效率低、交互不直观的问题,适合中高级 .NET 开发者用于项目功能改造与技术储备。资源包共 76 …

2026/9/28 12:28:02

比特币节点搭建实战:服务器定价模型与加密通讯原理解析

我习惯把零散的想法按编号存成笔记,周末整理文件夹时翻到一条写着"13-BTC-思考"的旧记录。内容是一段从技术社区里截取的信息:一条以 BTC 计价、标注着单台服务器报价的服务文案,末尾附带了一个叫 qTox 的加密通讯工具下载提示。信…

2026/9/28 12:28:02

YOLO车辆检测数据集实战:从标签校验到训练避坑指南

简介:针对 YOLO 系列算法的车辆检测数据集,涵盖小型车、自行车、公交车、卡车四类目标,适合使用 YOLOv5、YOLOv7、YOLOv8、YOLOv9、YOLOv10、YOLO11 的计算机视觉开发者学习和算法验证。资源已划分好训练集与验证集,附带数据集配置…

2026/9/28 13:23:06

Agentic Execution(ax):面向智能体协同的K8s原生编排层

1. 项目概述:从“ax”这个极简标题里,挖出一个正在爆发的技术新范式你刷到“ax”这个词,第一反应可能是缩写、代号、甚至某个电机型号——比如热搜里提到的“直流无刷电机ax by cz怎么划分”,听起来像机械设计里的坐标系命名。但如…

2026/9/28 13:23:06

LangChain4j + LangGraph4j:Java低代码智能体工作流平台架构实战

1. 为什么要在 Java 生态里折腾智能体工作流先说结论:如果你是一个 Java 后端团队,手上已经有一堆 Spring Boot 服务、权限体系、审批流、数据源,现在业务方跑过来跟你说“我们要接大模型,要能编排、能拖拽、能跑多步任务”&#…

2026/9/28 13:23:06

阶梯碳交易下含P2G-CCS与燃气掺氢的虚拟电厂优化调度

最近在复现一个课题,就是标题里这串字:基于阶梯碳交易的含 P2G-CCS 耦合和燃气掺氢的虚拟电厂优化调度。名字又长又绕,拆开看其实就是四件事:虚拟电厂、阶梯碳交易、P2G-CCS 耦合、燃气掺氢。说白了,就是在一个园区级的…

2026/9/28 13:18:06

混合流水车间调度HFSSPW:工人约束建模与NSGA-II启发式解码实践

HFSSPW这篇文章我断断续续做了一年多,从最初的建模陷阱到最终的Matlab代码框架,中间重写了三版解码器。最初我以为难点在进化算法,后来才意识到,真正拉开差距的是解码策略。今天把完整的求解思路、代码实现的细节和踩坑记录整理出…

2026/9/28 3:03:23

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/28 6:05:15

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/28 6:07:41

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/28 0:02:03

广州外贸网站建设推广:从零搭建全流程拆解与真实报价避坑

广州外贸网站建设推广:从零搭建全流程拆解与真实报价避坑 改个需求建站公司拖一周,后台改个文案还得再交一笔“技术维护费”。这种憋屈事儿,做外贸的朋友太熟悉了。很多老板在找广州外贸网站建设推广服务商时,光盯着首页好不好看,却忽略了从零搭建一个能…

2026/9/28 0:02:04

搞懂百度竞价推广价格,网站性能优化别掉链子

搞懂百度竞价推广价格,网站性能优化别掉链子 网站突然打不开,浏览器弹出红色警告“此网站存在安全风险”,后台一看全是乱码代码和奇怪的跳转链接。这种网站被黑挂马的绝望感,很多刚转行做网站的朋友都经历过,尤其是那些为了省几百块钱服务器费用的新手。…

2026/9/25 20:55:38

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/26 19:58:38

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/28 1:59:25

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑