news 2026/9/10 4:11:19

基于YOLOv8和PyTorch的苹果成熟度检测实现指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于YOLOv8和PyTorch的苹果成熟度检测实现指南

简介:一份基于PyTorch与YOLOv8的苹果成熟度检测完整项目,面向毕业设计、课程设计及项目开发者,解决从苹果图像采集标注、模型训练到推理部署的全流程需求,支持一键运行,适合快速搭建目标检测实验环境。压缩包共2000个文件,大小约44.08MB,核心内容包含约1000张苹果图片及对应txt标注文件(用于目标框位置与成熟度类别标注)、Python训练与推理脚本、yaml模型和数据配置、Markdown说明文档,同时附带预训练权重pt文件及Jupyter示例,目录结构严谨,便于按模块检索学习。已有388人学习使用,作为计算机视觉方向课程项目或毕设方案具有一定参考价值。项目提供完整数据集与分步说明,可直接复现训练、评估与导出流程,也可针对自定义数据调整参数进行迁移学习,有效缩短开发周期,辅助完成实验报告与功能演示。

1. 苹果成熟度检测为什么选 YOLOv8 + PyTorch

在果园或分选线上,苹果往往互相遮挡,成熟度判断不能只看整张图。直接把图片塞给分类网络的做法,遇到多个不同熟度的苹果就会失效。苹果成熟度检测本质上是一个目标检测问题,既要定位每个苹果,又要区分未熟、半熟、成熟。YOLOv8 把定位和分类放进一个网络,配合 PyTorch 的动态图生态,很适合毕业设计和课程设计从训练做到演示。

Ultralytics 官方库把数据组织、训练命令都封装好了,新手不用手写数据加载器;有经验的人也可以继续压榨性能,比如换 Backbone、导出 ONNX 部署到边缘设备。下面从数据、训练、推理和落地四个环节拆解,所有代码按“新增一个数据集”的视角写,方便迁移到其他农产品检测。

2. YOLOv8 模型结构与苹果成熟度数据集准备

2.1 YOLOv8 的目标检测头与 C2f 模块

YOLOv8 的网络结构仍然是 Backbone-Neck-Head 的三段式设计。Backbone 里最核心的 C2f 模块把特征图分成两支,一支做 1x1 卷积降维,另一支经过多个 Bottleneck 后再拼接,最后再融合。这种结构让梯度可以跨层回传,深层和浅层信息都保留得比较完整,对苹果这种从远处小目标到近景大目标都存在的任务是有利的。

和 YOLOv5 不一样的是,YOLOv8 的检测头换成了 Anchor-Free,直接在特征图上回归目标中心和边框,省去了预先聚类 Anchor 的环节,后处理也更简单。很多人以为 YOLOv8 只是把 v5 改了个名,其实它把分类分支和回归分支解耦,并且去掉了 Objectness 分支,推理时的输出维度也变了。理解这一点,后面导出 ONNX 处理输出时就不会懵。

2.2 苹果成熟度怎么定义类别

目标检测的数据集质量决定模型上限。苹果成熟度没有绝对标准,但做项目必须给一个可标注、可衡量的定义。我建议分成三类:unripe(绿色为主)、half_ripe(黄绿或淡红)、ripe(红色为主)。不要分五级,标注员自己都会标乱。

类别名颜色特征标注建议备注
unripe绿色为主,果肉硬完整可见的苹果,遮挡超过一半不标防止背景误检
half_ripe黄绿、淡红颜色转折明显最容易和 ripe 混淆
ripe红色或深红确保光照下颜色可辨阴影下需要补光

如果画面里经常有叶子挡到苹果,可以额外加一个 leaf 类,把被叶子遮挡超过 1/3 的苹果标成 leaf,让网络学习到“这部分不用检”。这样反而能降低苹果类别的误检率。类别不要贪多,控制在 3~4 个,课程设计完全够用。

2.3 用 LabelImg 标注并生成 YOLO 格式数据集

YOLOv8 的训练标注文件是 txt,每行格式为:类别id x_center y_center width height,坐标都是归一化比例值。我推荐用 LabelImg 的 YOLO 模式直接标注,省去转格式。如果你已经有一批 Pascal VOC 的 xml 标注,可以用下面这段脚本批量转换成 YOLO txt:

import os import xml.etree.ElementTree as ET classes = ["unripe", "half_ripe", "ripe", "leaf"] def xml_to_yolo(xml_path, out_dir): tree = ET.parse(xml_path) root = tree.getroot() img_w = int(root.find("size").find("width").text) img_h = int(root.find("size").find("height").text) lines = [] for obj in root.findall("object"): name = obj.find("name").text if name not in classes: continue cls_id = classes.index(name) box = obj.find("bndbox") xmin = int(box.find("xmin").text) ymin = int(box.find("ymin").text) xmax = int(box.find("xmax").text) ymax = int(box.find("ymax").text) x_c = ((xmin + xmax) / 2) / img_w y_c = ((ymin + ymax) / 2) / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h lines.append(f"{cls_id} {x_c:.6f} {y_c:.6f} {w:.6f} {h:.6f}") txt_name = os.path.basename(xml_path).replace(".xml", ".txt") with open(os.path.join(out_dir, txt_name), "w", encoding="utf-8") as f: f.write("\n".join(lines))

代码逻辑很简单:从 xml 里读取原图宽高和 bndbox 绝对坐标,转换成中心点加宽高的归一化数值。注意classes的顺序一旦确定,后面训练配置里的 names 必须保持一致。如果顺序乱了,框可能画对位置,标签却错了,这类错误很难排查。

转换完 txt 后,再写一个apple_data.yaml,这是 Ultralytics 训练时的数据入口:

path: ./apple_data train: images/train val: images/val test: images/test names: 0: unripe 1: half_ripe 2: ripe 3: leaf

path可以是相对路径,但我更建议用绝对路径,防止不同机器上工作目录不同导致找不到图片。图片和 txt 文件的文件名必须一一对应,扩展名可以不同,但主名要一致。

2.4 数据增强与样本平衡

苹果成熟度检测最常见的问题是“成熟果样本多、未熟样本少”,尤其在你只收集了某些时段图片的时候。为了平衡,除了多拍,还要靠增强。Ultralytics 自带训练时增强,比如hsv_hdegreesfliplr等参数,直接在命令行控制即可。如果离线增强,可以用 Albumentations,它会同步更新 bbox:

import albumentations as A transform = A.Compose([ A.HorizontalFlip(p=0.5), A.RandomBrightnessContrast(p=0.3), A.Rotate(limit=15, p=0.3), ], bbox_params=A.BboxParams(format="yolo", label_fields=["labels"])) # 假设 img 是 BGR 或 RGB 数组,bboxes 是归一化的 [[x_c, y_c, w, h], ...] # transformed = transform(image=img, bboxes=bboxes, labels=labels)

bbox_params设成yolo后,旋转和翻转会自动换算框坐标,不需要自己改。这里要小心的是Rotate对于旋转角较大时,框会发生形变,建议角度控制在 15 度以内,否则模型的边框回归会学得很纠结。

3. 在 PyTorch 下训练 YOLOv8:环境、命令与参数调优

3.1 PyTorch 与 Ultralytics 环境安装要点

训练前先搭 PyTorch 环境。是否需要 GPU 取决于你的数据集规模:500 张以下用 CPU 也能跑,但 50 个 epoch 可能要四五个小时;有 NVIDIA 显卡还是尽量用 GPU。安装时先看驱动支持的最高 CUDA 版本,再选择对应的 PyTorch。常见组合是 CUDA 11.8 或 12.1,对应 PyTorch 2.x。我通常在 Anaconda 里建独立环境:

conda create -n yolo python=3.10 conda activate yolo pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics

安装完先确认 GPU 是否可用,不然训练时才发现用的是 CPU 就晚了:

import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else "CPU")

如果输出False,很大概率是装了 CPU 版 PyTorch,或者显卡驱动太旧。重新安装对应 CUDA 版本的 PyTorch 即可。注意 Python 版本尽量选 3.10,有部分 3.12 的朋友反馈 ultralytics 依赖解析会出问题。

3.2 YOLOv8 训练自己的苹果数据集:最小命令

数据集目录准备好后,训练命令很短,这是 Ultralytics 做得好的地方:

yolo detect train data=apple_data.yaml model=yolov8n.pt epochs=50 batch=16 imgsz=640 device=0

model=yolov8n.pt会自动下载预训练权重,并作为初始权重,不是从零开始训练。n 是 nano 版本,显存占用小、训练快,课程设计先用它跑通全流程。想提精度可以换成yolov8s.ptyolov8m.pt,但显存消耗会成倍增长,普通 8G 显卡建议用 s。

这里要注意,data参数指向的是apple_data.yaml,Ultralytics 会根据里面的trainval路径自动寻找图片。运行后会在runs/detect/train下保存权重和训练曲线。

3.3 关键训练参数表

我整理了一份常用参数表,帮助你在项目答辩时解释参数选择的理由:

参数常用值影响坑点
modelyolov8n.pt / yolov8s.pt模型体量与速度需要预训练文件
dataapple_data.yaml数据配置路径错会直接报错
epochs50~100拟合程度过大过拟合,过小欠拟合
imgsz640输入分辨率苹果小就保持 640
batch16~32占显存大小OOM 时优先降这个
patience20早停轮数模型不升就停
lr00.01初始学习率迁移学习时可调小
freeze10冻结前几层小数据集防止破坏特征

batch在 8G 显存下跑yolov8n一般能开到 32。如果报 CUDA Out Of Memory,别急着换小模型,先降低 batch 到 8 或者 4,效果差距并不大。

3.4 训练过程观察与损失函数曲线绘制

训练时终端会输出box_losscls_lossdfl_loss,还有mAP50mAP50-95。第一次训练的人容易只看 mAP,其实要先看 loss 是否稳定下降。如果 loss 震荡不收敛,优先检查数据集,再考虑调学习率。

Ultralytics 训练完成后会在结果目录生成results.csv,我用一段脚本画损失函数曲线图,直接放进论文或答辩 PPT:

import pandas as pd import matplotlib.pyplot as plt res = pd.read_csv("runs/detect/train/results.csv") plt.figure(figsize=(10, 4)) plt.subplot(1, 2, 1) plt.plot(res["epoch"], res["train/box_loss"], label="box_loss") plt.plot(res["epoch"], res["train/cls_loss"], label="cls_loss") plt.legend() plt.title("Training Loss") plt.subplot(1, 2, 2) plt.plot(res["epoch"], res["val/mAP50-95"], label="mAP50-95") plt.legend() plt.title("Validation mAP") plt.savefig("loss_curve.png", dpi=200)

代码从results.csv中读训练损失和验证 mAP 两个子图。不同 Ultralytics 版本的列名可能不一样,如果 KeyError 就先print(res.columns)查看真实列名。保存的loss_curve.png可以直接用来展示模型收敛过程。

3.5 从预训练权重迁移与超参数微调

小数据集训练一定要用迁移学习。直接用官方预训练权重比随机初始化快不少,精度也高很多。如果你的苹果图片不足 300 张,我建议先冻结部分 Backbone 训练:

yolo detect train data=apple_data.yaml model=yolov8n.pt epochs=30 freeze=10 lr0=0.005

freeze=10表示冻结前 10 层,lr0调小一点防止破坏预训练特征。跑完一轮后,再减少freeze或解冻所有层,用更小学习率微调。这样两阶段训练对成熟度检测尤其有效,因为颜色和纹理特征在预训练模型里已经有了,我们只需要微调检测器。

4. 苹果成熟度检测推理实现:从图片到摄像头的完整代码

4.1 图片推理:读取模型并检测成熟度

训练结束后,runs/detect/train/weights/下会有best.ptlast.pt。推理时优先用best.pt。下面这段代码是图片推理的最小实现:

from ultralytics import YOLO model = YOLO("runs/detect/train/weights/best.pt") results = model.predict("apple_01.jpg", conf=0.25, device="cpu", save=True) result = results[0] boxes = result.boxes.xyxy.cpu().numpy() classes = result.boxes.cls.cpu().numpy().astype(int) scores = result.boxes.conf.cpu().numpy() for box, cls, score in zip(boxes, classes, scores): name = result.names[cls] x1, y1, x2, y2 = [int(v) for v in box] print(f"{name}: {score:.3f} at ({x1},{y1},{x2},{y2})")

result.boxes.xyxy是四个角坐标,cls是类别索引,conf是置信度。conf=0.25会过滤掉低分框,如果背景误检多就调到 0.4,如果漏检多就降到 0.2。save=True会把画好框的结果图保存到当前目录,方便快速查看。

4.2 应用推理:统计不同成熟度苹果数量

毕业设计里通常要输出“多少个未熟、多少熟”,不能只画框。我在项目里会写一个统计函数:

import cv2 img = cv2.imread("apple_01.jpg") result = model.predict(img, conf=0.25)[0] counts = {"unripe": 0, "half_ripe": 0, "ripe": 0} for box, cls, score in zip(result.boxes.xyxy, result.boxes.cls, result.boxes.conf): name = result.names[int(cls)] if name in counts: counts[name] += 1 x1, y1, x2, y2 = [int(v) for v in box] color = (0, 255, 0) if name == "ripe" else (0, 165, 255) if name == "half_ripe" else (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, f"{name} {score:.2f}", (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) cv2.imwrite("output.jpg", img) print(counts)

代码会按类别画不同颜色的框,并在终端输出统计结果。实际使用中如果发现成熟果和木板箱的颜色很像,可以在采集端增加照明,训练集里多放一些不同背景的样本,比调颜色阈值更可靠。

4.3 摄像头实时识别:读取视频流

答辩演示时经常要现场连摄像头。用 VideoCapture 读取每一帧,再用plot()快速画出结果:

import cv2 from ultralytics import YOLO model = YOLO("best.pt") cap = cv2.VideoCapture(0) while cap.isOpened(): ret, frame = cap.read() if not ret: break results = model.predict(frame, conf=0.3, device=0, verbose=False) annotated = results[0].plot() cv2.imshow("Apple Ripeness", annotated) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() cv2.destroyAllWindows()

plot()是官方封装好的画框方法,不需要手动处理坐标。device=0表示用 GPU,没有 GPU 就改成cpu。摄像头编号在笔记本上可能是 0 或 1,如果打开黑屏就多试几个编号。

4.4 导出为 ONNX 以加速部署

CPU 上跑 YOLOv8n 视频流一般只有十几帧,导出成 ONNX 后用 ONNXRuntime 推理能稍微快一点,也是嵌入式部署的前提:

yolo export model=best.pt format=onnx opset=12

导出后的best.onnx可以用 ONNXRuntime 加载,但要注意输出后处理逻辑和原始 PyTorch 模型不完全一样。如果是带 NMS 的版本,直接取输出即可;如果是不带 NMS 的版本,需要自己解析xywh和置信度。我建议课程设计阶段还是在 PyTorch 环境里做推理,把 ONNX 导出当作加分项写进报告。

5. 毕业设计落地技巧:模型评估、导出与演示优化

5.1 从训练结果中提取评估指标

答辩不能只会说“效果不错”,要用数据说话。用model.val()可以拿到验证集上的核心指标:

from ultralytics import YOLO model = YOLO("runs/detect/train/weights/best.pt") metrics = model.val(data="apple_data.yaml") print(metrics.box.map50) print(metrics.box.map) print(metrics.box.precision) print(metrics.box.recall)

map50是 IoU 阈值 0.5 的 mAP,map是 0.5 到 0.95 的平均 mAP。对苹果成熟度检测,我更看重 recall,因为漏掉一个成熟果比多画一个框问题更严重。如果某个类别 recall 明显低,回到数据里补充该类别难例。

5.2 做一个极简 Gradio 演示界面

答辩现场演示,用 Gradio 做一个上传图片就能出结果的界面非常加分。代码量很少:

import gradio as gr from ultralytics import YOLO model = YOLO("best.pt") def detect(img): result = model.predict(img, conf=0.25)[0] return result.plot() gr.Interface(fn=detect, inputs="image", outputs="image", title="苹果成熟度检测").launch()

这条命令会启动一个本地 Web 页面,答辩时可以展示识别效果,也可以让评委直接传图片试,比命令行演示直观得多。

5.3 常见坑位与规避

环境问题占了我遇到问题的一半以上。PyTorch 和 CUDA 版本不匹配,直接导致cuda.is_available()为 False。检查时用nvidia-smi确认驱动上限,再去 PyTorch 官网选择对应版本。Windows 下路径不能带中文,yaml路径错了就会报AssertionError。另外,如果显存不够,优先降batch,而不是降imgsz

5.4 项目目录结构建议

一个清晰的项目结构能减少答辩时跑不通的风险:

apple_ripeness/ ├── data/ │ ├── images/ │ ├── labels/ │ └── apple_data.yaml ├── runs/ │ └── detect/train/weights/best.pt ├── scripts/ │ ├── train.py │ ├── detect.py │ └── gradio_app.py ├── requirements.txt └── README.md

把训练、推理、演示各自拆成脚本,依赖写进requirements.txt,换一台电脑也能十分钟跑通。视频演示尽量用提前录好的 mp4 代替真实摄像头,现场灯光、驱动不可控,录好的视频更稳妥,也能反复展示模型在不同场景的表现。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 4:11:10

低延迟播放与YOLO实时目标检测:同管线融合方案详解

1. 项目拆析:播放、分析为什么必须放进同一条管线里SmartMediaKit 在我这边是一个偏工程向的媒体组件,主要负责低延迟播放、拉流、转封装、解码、渲染这一整条链路。YOLO 则是目前落地最广的实时目标检测模型,检测、分割、姿态估计都能做。把…

作者头像 李华
网站建设 2026/9/10 4:10:05

通义千问换帅背后:大模型战略失焦与商业化困局

1. 换帅不是导火索,是长期钝感的结算时刻大模型的牌桌上,没有人能靠一款产品吃遍天,但一旦连续几个回合让外界感觉“你找不到方向”,换人就是悬在头顶的必然结局。这次通义千问换帅,被很多人解读成阿里AI终于要踩油门了…

作者头像 李华
网站建设 2026/9/10 4:09:17

Android UsbHost与PC libusb双向通信实现字符与文件传输

简介:面向Android开发者的USB双向通信完整工程资源,解决APP与PC之间通过USB进行字符和文件传输的需求,涵盖USB Host/Device模式原理、权限声明、设备热插拔监听、端点读写等核心环节。压缩包内共819个文件,其中256个JSON配置、270…

作者头像 李华
网站建设 2026/9/10 4:08:46

CANN/ge错误信息获取API

GEGetErrorMsgV2 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、TensorFlo…

作者头像 李华