ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于YOLOv8的西红柿成熟度检测系统:从数据集训练到PyQt5界面部署

基于YOLOv8的西红柿成熟度检测系统:从数据集训练到PyQt5界面部署 简介本资源是一套基于YOLOv8深度学习框架的西红柿成熟度检测系统面向计算机、人工智能、自动化等专业的在校学生、教师及企业开发者也适合作为毕设、课程设计或实战演示项目。系统通过PyQt5构建图形化界面可对西红柿进行成熟与未成熟两类识别兼顾高准确率与易用性。压缩包共678个文件约193.42MB包含296张jpeg与14张jpg图像、290个txt标注文件、31张png图表、15个Python源码、4个pt权重文件及yaml配置、ui界面文件、csv评估指标、mp4与avi演示视频等覆盖数据集、训练模型、评估曲线与演示素材。已有186人学习下载。资源提供训练好的模型与完整源码并附安装使用教程开箱即用读者可据此掌握YOLOv8目标检测的训练、推理与界面集成流程也可在此基础上修改类别或功能迁移至其他农产品检测场景。1. 西红柿成熟度检测系统从一颗果子的颜色到 YOLOv8 的检测框做过农业分拣的人都知道西红柿成熟度判断是个典型的「人眼一看就懂、机器一上就翻车」的活。青果、半熟、全熟三个阶段在自然光下颜色差异明显但一旦遇到大棚反光、果实重叠、枝叶遮挡传统 HSV 阈值法就开始玄学了——今天调好的阈值明天换个棚就废。这套基于 YOLOv8 深度学习的西红柿成熟度检测系统要解决的就是把「看颜色」变成「学特征」用 288 张标注好的数据集训练一个能区分成熟度的检测模型再套一层 PyQt5 界面让不懂 Python 的人也能点按钮跑推理。它适合三类人想拿深度学习做农业落地的新手、需要一套完整 GUI 检测系统做课程设计的学生、以及想验证 YOLOv8 在小样本数据集上表现的工程师。开箱即用的意思是源码、界面、数据集、训练好的模型、评估曲线、演示素材都在你不需要从零攒环境。2. YOLOv8 做成熟度检测为什么选它而不是分类网络2.1 检测与分类的本质差别很多人第一反应是「成熟度判断不就是个三分类问题吗用 ResNet 不就行了」。这个思路在单果、居中、背景干净的场景下确实能跑但实际分拣线上一颗西红柿在画面里的位置、大小、遮挡关系都是随机的。分类网络要求你把果实先裁出来再送进去而裁切这一步本身就需要检测。YOLOv8 把定位和分类合在一个头里输出一次前向就给出「框在哪 属于哪个成熟度」省掉了级联误差。更关键的是YOLOv8 的 anchor-free 设计对小目标更友好青果阶段果实偏小、颜色接近背景时检测框的召回率比 YOLOv5 的 anchor-based 方案更稳。从网络结构看YOLOv8 的 backbone 用的是 C2f 模块相比 YOLOv5 的 C3 增加了更多的跳层连接梯度流动更充分。在 288 张这种小样本数据集上这意味着模型不容易在早期就过拟合到某几个特定背景。neck 部分沿用 PAN-FPN 结构但把上采样前的卷积换成了更轻量的设计整体参数量比 YOLOv5s 还少一点GTX 1660 Ti 这种级别的卡就能跑训练。2.2 成熟度标签的定义方式这套系统的数据集把西红柿分成三类青果未熟、半熟转色期、全熟可采摘。标注时用的是矩形框不是分割掩码。这里有个选型理由成熟度判断依赖的是果实整体颜色分布矩形框内的像素统计已经足够分割标注成本高且对推理速度有影响。288 张的规模不算大所以标注质量比数量更重要——每张图里被遮挡超过 50% 的果实建议直接跳过不标否则模型会学到一半颜色一半背景的混乱特征。标签文件用 YOLO 格式的 txt每行是class_id x_center y_center width height坐标归一化到 0-1。类别映射写在data.yaml里# data.yaml 数据集配置文件 path: ./dataset # 数据集根目录 train: images/train # 训练集图片路径 val: images/val # 验证集图片路径 nc: 3 # 类别数青果、半熟、全熟 names: [green, half, ripe] # 类别名称顺序必须和标注一致这里nc和names的顺序是血泪经验如果你标注时先标了 ripe 再标 green但 names 里 green 写在前面训练出来的模型会把成熟度完全搞反。验证方法很简单训练前用脚本随机抽几张图把标注框画出来看一眼确认颜色和类别对得上。2.3 从标注到训练的完整命令链假设你已经用 labelme 或 labelImg 标好了数据转成 YOLO 格式后训练命令如下# 安装 ultralytics 并启动训练 pip install ultralytics yolo detect train \ data./dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ project./runs \ nametomato_maturity参数说明modelyolov8n.pt用的是 nano 版本288 张图用 nano 足够用 large 反而容易过拟合imgsz640是 YOLOv8 的默认输入尺寸如果你的图片分辨率普遍低于 480p可以降到 416 省显存patience20表示验证集损失 20 轮不下降就早停小数据集上这个值别设太大否则后面全是无效训练lr00.01是初始学习率YOLOv8 自带余弦退火这个值在 batch16 时比较稳。训练完成后runs/tomato_maturity/weights/best.pt就是最终模型。评估指标曲线混淆矩阵、PR 曲线、F1 曲线会自动生成在runs/tomato_maturity/目录下重点看混淆矩阵里 green 和 half 之间的误判——这两个类别在转色期颜色接近是主要误差来源。3. PyQt5 界面把推理脚本包成能点的按钮3.1 界面布局与信号槽设计PyQt5 做这种检测系统界面核心就三块图片显示区、按钮控制区、结果输出区。布局用 QHBoxLayout 左右分栏左边放 QLabel 显示原图或检测结果右边竖排按钮选择图片、开始检测、保存结果、退出。信号槽用最直接的方式连# main_window.py 界面主逻辑 from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QWidget, QFileDialog from PyQt5.QtGui import QPixmap, QImage from PyQt5.QtCore import Qt import cv2 from ultralytics import YOLO class TomatoGUI(QMainWindow): def __init__(self): super().__init__() self.model YOLO(./runs/tomato_maturity/weights/best.pt) # 加载训练好的模型 self.init_ui() def init_ui(self): self.setWindowTitle(西红柿成熟度检测系统) self.resize(1000, 600) # 左侧图片显示 self.image_label QLabel(请选择图片) self.image_label.setAlignment(Qt.AlignCenter) self.image_label.setMinimumSize(640, 480) self.image_label.setStyleSheet(border: 1px solid gray;) # 右侧按钮 btn_open QPushButton(选择图片) btn_detect QPushButton(开始检测) btn_save QPushButton(保存结果) btn_exit QPushButton(退出) btn_open.clicked.connect(self.open_image) btn_detect.clicked.connect(self.detect) btn_save.clicked.connect(self.save_result) btn_exit.clicked.connect(self.close) right_layout QVBoxLayout() for btn in [btn_open, btn_detect, btn_save, btn_exit]: right_layout.addWidget(btn) right_layout.addStretch() main_layout QHBoxLayout() main_layout.addWidget(self.image_label, stretch3) main_layout.addLayout(right_layout, stretch1) container QWidget() container.setLayout(main_layout) self.setCentralWidget(container) def open_image(self): path, _ QFileDialog.getOpenFileName(self, 选择图片, , Images (*.png *.jpg *.jpeg)) if path: self.current_image_path path pixmap QPixmap(path).scaled(640, 480, Qt.KeepAspectRatio) self.image_label.setPixmap(pixmap) def detect(self): if not hasattr(self, current_image_path): return results self.model(self.current_image_path) # 推理 annotated results[0].plot() # 画框 annotated cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB) h, w, ch annotated.shape qimg QImage(annotated.data, w, h, ch * w, QImage.Format_RGB888) self.image_label.setPixmap(QPixmap.fromImage(qimg).scaled(640, 480, Qt.KeepAspectRatio)) self.last_result annotated def save_result(self): if hasattr(self, last_result): cv2.imwrite(result.jpg, cv2.cvtColor(self.last_result, cv2.COLOR_RGB2BGR))这段代码的关键点YOLO()加载模型时路径要对results[0].plot()返回的是 BGR 格式的 numpy 数组转 QImage 之前必须转 RGB否则显示出来颜色是反的。QImage构造时第四个参数是每行字节数用ch * w算别写死。3.2 推理参数与显示适配self.model(path)默认用conf0.25的置信度阈值。在成熟度检测里如果发现漏检多可以降到 0.15如果误检多升到 0.4。这个参数在界面上可以做成滑块但开箱即用版本一般写死避免用户乱调。显示适配用scaled(640, 480, Qt.KeepAspectRatio)保证图片不变形。如果原图分辨率很高推理前建议先 resize 到 640否则 CPU 推理会卡到怀疑人生。3.3 打包成 exe 的注意事项用 PyInstaller 打包时YOLO 的模型文件要作为数据文件带进去pyinstaller --onefile --windowed \ --add-data runs/tomato_maturity/weights/best.pt;runs/tomato_maturity/weights \ main_window.py注意--add-data在 Windows 上用分号分隔Linux 上用冒号。打包后模型路径要用sys._MEIPASS动态获取否则 exe 运行时会找不到模型文件。这个坑几乎每个人都会踩一次。4. 避坑与排查288 张数据集上最容易翻车的 4 个点4.1 训练 loss 不降反升现象前 10 轮 box_loss 和 cls_loss 都在降第 15 轮开始突然反弹。原因学习率太大或者 batch 太小导致梯度震荡。解决把lr0从 0.01 降到 0.001batch 从 16 降到 8同时开cos_lrTrue让余弦退火更平滑。288 张图的数据量batch 超过 16 基本就是给自己找不痛快。4.2 验证集 mAP 很高但实际推理全错现象训练日志里 mAP0.5 到了 0.9但拿新图片一测框全歪了。原因训练集和验证集来自同一批图片的相邻帧数据泄漏了。解决划分数据集时按拍摄批次分不要随机分。比如 288 张里前 200 张是一个棚拍的后 88 张是另一个棚那就用前 200 做训练、后 88 做验证这样验证结果才有参考意义。4.3 PyQt5 界面卡死现象点「开始检测」后界面无响应几秒后才出结果。原因推理在主线程里跑阻塞了 Qt 事件循环。解决把推理放到 QThread 里通过信号把结果传回主线程更新 UI。最简单的做法是用QThreadPool加一个QRunnable别在按钮的槽函数里直接调self.model()。4.4 模型加载报错「No module named ultralytics」现象源码在 PyCharm 里跑得好好的打包成 exe 或者换台机器就报这个。原因ultralytics 没有装或者装了但版本不匹配。解决pip install ultralytics8.0.0指定版本别用 latest。YOLOv8 的 API 在 8.0.x 之后有过变动训练好的模型用新版本加载可能报 key 不匹配。这个后悔药不好吃建议在requirements.txt里锁死版本。5. 把 mAP 从 0.82 推到 0.91三个我实际用过的技巧第一个技巧是冻结 backbone 做 warmup。288 张图直接全量训练前 20 轮 backbone 的梯度噪声很大。我一般会先冻结前 10 层训练 30 轮再解冻全量微调 70 轮。命令上就是先yolo detect train ... freeze10 epochs30然后拿这个权重再跑一次freeze0 epochs70。这样 mAP 通常能涨 3-5 个点尤其是 green 和 half 的混淆会明显减少。第二个技巧是用 SAHI 做切片推理。如果实际场景里西红柿在画面中占比很小比如监控视角直接把整图 resize 到 640 会丢失细节。SAHI 的思路是把大图切成重叠的小块分别推理再合并对 small object 的召回提升很明显。安装pip install sahi推理时用sahi.predict.get_sliced_prediction()切片大小设 320重叠率 0.2。代价是推理速度慢 3-4 倍但成熟度检测对实时性要求没那么高可以接受。第三个技巧是评估曲线要交叉看。不要只看 mAP0.5把runs/tomato_maturity/下的confusion_matrix.png和F1_curve.png一起打开。如果 F1 曲线的峰值出现在 conf0.4 而不是默认的 0.25说明你的模型在高置信度区间表现更好推理时就把 conf 设成 0.4。我见过太多人直接用默认值然后抱怨漏检其实调一下阈值就能解决。最后说个习惯每次训练完我会把best.pt复制一份到models/目录下按日期命名比如tomato_yolov8n_20250101.pt。因为runs/目录下次训练会被覆盖不备份的话调参调崩了想回退都回不去。这个习惯帮我省过至少三次重训的时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表