基于深度学习YOLOv10的苹果成熟度检测系统(YOLOv10+YOLO数据集+UI界面+Python项目源码+模型)

一、项目介绍

摘要

本项目基于YOLOv10目标检测算法开发了一套苹果成熟度自动检测系统,能够准确识别并分类苹果的五个成熟度等级:20%成熟、50%成熟、75%成熟、100%成熟以及腐烂苹果。系统使用包含2728张标注图像的数据集(训练集2144张,验证集359张,测试集225张)进行训练和评估,实现了对苹果成熟状态的精确识别。该技术可应用于果园自动化管理、智能采摘机器人、水果品质分级等农业场景,显著提高水果采收效率和质量控制水平,减少人工判断的主观性和误差,为现代农业智能化发展提供技术支持。

项目意义

苹果成熟度检测在农业生产和食品加工领域具有重要应用价值。传统的人工检测方法效率低下且主观性强,难以满足大规模商业化生产的需求。本项目的实施具有以下多重意义:

  1. 农业智能化转型:通过计算机视觉技术实现苹果成熟度的自动化检测,推动传统农业向精准农业、智慧农业转型。

  2. 采收效率提升:系统可24小时不间断工作,检测速度远超人工,特别适合大规模果园应用,显著降低人力成本。

  3. 品质控制标准化:统一的算法标准避免了人工判断的主观差异,确保水果采收和分级的客观性和一致性。

  4. 减少采后损失:准确识别腐烂苹果可及时剔除问题果实,防止交叉感染,降低采后损失率。

  5. 数据驱动决策:系统可记录成熟度分布数据,为果园管理、采收时间规划提供科学依据。

  6. 技术推广价值:本项目的技术框架可扩展至其他水果的成熟度检测,具有广泛的适用性和推广潜力。

目录

一、项目介绍

摘要

项目意义

二、项目功能展示

系统功能

图片检测

视频检测

摄像头实时检测

三、数据集介绍

数据集概述

数据集特点

数据集配置文件

数据集制作流程

四、项目环境配置

创建虚拟环境

pycharm中配置anaconda

安装所需要库

五、模型训练

训练代码

训练结果

六、核心代码

七、项目源码(视频下方简介内)


基于深度学习YOLOv10的苹果成熟度检测系统(YOLOv10+YOLO数据集+UI界面+Python项目源码+模型)_哔哩哔哩_bilibili

基于深度学习YOLOv10的苹果成熟度检测系统(YOLOv10+YOLO数据集+UI界面+Python项目源码+模型)

二、项目功能展示

系统功能

✅ 图片检测:可对图片进行检测,返回检测框及类别信息。

✅ 视频检测:支持视频文件输入,检测视频中每一帧的情况。

✅ 摄像头实时检测:连接USB 摄像头,实现实时监测。

参数实时调节(置信度和IoU阈值)

  • 图片检测

        该功能允许用户通过单张图片进行目标检测。输入一张图片后,YOLO模型会实时分析图像,识别出其中的目标,并在图像中框出检测到的目标,输出带有目标框的图像。 

  • 视频检测

        视频检测功能允许用户将视频文件作为输入。YOLO模型将逐帧分析视频,并在每一帧中标记出检测到的目标。最终结果可以是带有目标框的视频文件或实时展示,适用于视频监控和分析等场景。

  • 摄像头实时检测

        该功能支持通过连接摄像头进行实时目标检测。YOLO模型能够在摄像头拍摄的实时视频流中进行目标检测,实时识别并显示检测结果。此功能非常适用于安防监控、无人驾驶、智能交通等应用,提供即时反馈。

核心特点:

  • 高精度:基于YOLO模型,提供精确的目标检测能力,适用于不同类型的图像和视频。
  • 实时性:特别优化的算法使得实时目标检测成为可能,无论是在视频还是摄像头实时检测中,响应速度都非常快。
  • 批量处理:支持高效的批量图像和视频处理,适合大规模数据分析。

三、数据集介绍

数据集概述

本项目构建了一个专业化的苹果成熟度检测图像数据集,总样本量2728张,分为训练集(2144张)、验证集(359张)和测试集(225张)。数据集包含五个精细定义的成熟度类别:

  1. 20%成熟度:苹果呈现明显青绿色,体积发育完全但颜色未转变

  2. 50%成熟度:开始出现黄绿色或淡红色,处于颜色转变初期

  3. 75%成熟度:大部分果面呈现成熟色泽,但仍有部分绿色区域

  4. 100%成熟度:完全呈现品种特征颜色,色泽均匀饱满

  5. 腐烂苹果:表面出现明显褐变、病斑或腐烂特征的果实

数据集特点

  1. 多样性保障

    • 采集场景涵盖果园自然光照、包装车间、实验室环境

    • 包含多个苹果品种(如富士、嘎啦、红元帅等)

    • 拍摄角度多样(正视、侧视、俯视、多果实重叠等)

    • 光照条件变化(自然光、补光灯、阴影等)

  2. 精细标注

    • 每个苹果实例均用矩形框精确标注

    • 成熟度分级由农业专家确认

    • 标注考虑了果实遮挡、枝叶干扰等现实情况

  3. 质量控制

    • 排除了模糊、过曝或严重遮挡的无效样本

    • 各类别样本数量经过平衡处理

    • 测试集完全独立采集,确保评估客观性

数据集配置文件

项目采用YOLO格式的数据集配置文件(如apple_dataset.yaml),主要包含以下内容:

train: F:\苹果成熟度数据集\train\images
val: F:\苹果成熟度数据集\valid\images
test: F:\苹果成熟度数据集\test\images

nc: 5
names: ['100-_ripeness', '20-_ripeness', '50-_ripeness', '75-_ripeness', 'rotten_apple']
 

数据集制作流程

  1. 原始数据采集

    • 使用专业数码相机和智能手机多设备采集

    • 拍摄距离确保果实清晰可见

    • 每个样本采集多角度照片

  2. 专业标注

    • 使用LabelImg等工具进行边界框标注

    • 由果树栽培专家指导确定成熟度分级标准

    • 标注结果经过三重校验

  3. 数据增强

    • 应用色彩抖动、随机旋转、镜像翻转

    • 添加模拟阴影和光照变化

    • 生成部分遮挡样本提高模型鲁棒性

  4. 数据集划分

    • 确保各子集在品种、成熟度、拍摄环境上分布一致

    • 同一棵树的果实不会同时出现在训练集和测试集

    • 测试集包含困难样本(严重遮挡、非常规姿态等)

  5. 质量验证

    • 计算各类别样本数量分布

    • 检查标注框的准确性和一致性

    • 验证图像与标注文件的对应关系

四、项目环境配置

创建虚拟环境

首先新建一个Anaconda环境,每个项目用不同的环境,这样项目中所用的依赖包互不干扰。

终端输入

conda create -n yolov10 python==3.9

激活虚拟环境

conda activate yolov10
 

安装cpu版本pytorch

pip install torch torchvision torchaudio

pycharm中配置anaconda

安装所需要库

pip install -r requirements.txt

五、模型训练

训练代码

from ultralytics import YOLOv10

model_path = 'yolov10s.pt'
data_path = 'datasets/data.yaml'

if __name__ == '__main__':
    model = YOLOv10(model_path)
    results = model.train(data=data_path,
                          epochs=500,
                          batch=64,
                          device='0',
                          workers=0,
                          project='runs/detect',
                          name='exp',
                          )
根据实际情况更换模型
yolov10n.yaml (nano):轻量化模型,适合嵌入式设备,速度快但精度略低。
yolov10s.yaml (small):小模型,适合实时任务。
yolov10m.yaml (medium):中等大小模型,兼顾速度和精度。
yolov10b.yaml (base):基本版模型,适合大部分应用场景。
yolov10l.yaml (large):大型模型,适合对精度要求高的任务。
  • --batch 64:每批次64张图像。
  • --epochs 500:训练500轮。
  • --datasets/data.yaml:数据集配置文件。
  • --weights yolov10s.pt:初始化模型权重,yolov10s.pt 是预训练的轻量级YOLO模型。

训练结果

六、核心代码

import sys
 
import cv2
import numpy as np
from PyQt5.QtWidgets import QApplication, QMessageBox, QFileDialog
from PyQt5.QtCore import QThread, pyqtSignal
from ultralytics import YOLOv10
from UiMain import UiMainWindow
import time
import os
 
 
class DetectionThread(QThread):
    frame_received = pyqtSignal(np.ndarray, np.ndarray, list)  # 原始帧, 检测帧, 检测结果
    finished_signal = pyqtSignal()  # 线程完成信号
 
    def __init__(self, model, source, conf, iou, parent=None):
        super().__init__(parent)
        self.model = model
        self.source = source
        self.conf = conf
        self.iou = iou
        self.running = True
 
    def run(self):
        try:
            if isinstance(self.source, int) or self.source.endswith(('.mp4', '.avi', '.mov')):  # 视频或摄像头
                cap = cv2.VideoCapture(self.source)
                while self.running and cap.isOpened():
                    ret, frame = cap.read()
                    if not ret:
                        break
 
                    # 保存原始帧
                    original_frame = frame.copy()
 
                    # 检测
                    results = self.model(frame, conf=self.conf, iou=self.iou)
                    annotated_frame = results[0].plot()
 
                    # 提取检测结果
                    detections = []
                    for result in results:
                        for box in result.boxes:
                            class_id = int(box.cls)
                            class_name = self.model.names[class_id]
                            confidence = float(box.conf)
                            x, y, w, h = box.xywh[0].tolist()
                            detections.append((class_name, confidence, x, y))
 
                    # 发送信号
                    self.frame_received.emit(
                        cv2.cvtColor(original_frame, cv2.COLOR_BGR2RGB),
                        cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB),
                        detections
                    )
 
                    # 控制帧率
                    time.sleep(0.03)  # 约30fps
 
                cap.release()
            else:  # 图片
                frame = cv2.imread(self.source)
                if frame is not None:
                    original_frame = frame.copy()
                    results = self.model(frame, conf=self.conf, iou=self.iou)
                    annotated_frame = results[0].plot()
 
                    # 提取检测结果
                    detections = []
                    for result in results:
                        for box in result.boxes:
                            class_id = int(box.cls)
                            class_name = self.model.names[class_id]
                            confidence = float(box.conf)
                            x, y, w, h = box.xywh[0].tolist()
                            detections.append((class_name, confidence, x, y))
 
                    self.frame_received.emit(
                        cv2.cvtColor(original_frame, cv2.COLOR_BGR2RGB),
                        cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB),
                        detections
                    )
 
        except Exception as e:
            print(f"Detection error: {e}")
        finally:
            self.finished_signal.emit()
 
    def stop(self):
        self.running = False
 
 
class MainWindow(UiMainWindow):
    def __init__(self):
        super().__init__()
 
        # 初始化模型
        self.model = None
        self.detection_thread = None
        self.current_image = None
        self.current_result = None
        self.video_writer = None
        self.is_camera_running = False
        self.is_video_running = False
        self.last_detection_result = None  # 新增:保存最后一次检测结果
 
        # 连接按钮信号
        self.image_btn.clicked.connect(self.detect_image)
        self.video_btn.clicked.connect(self.detect_video)
        self.camera_btn.clicked.connect(self.detect_camera)
        self.stop_btn.clicked.connect(self.stop_detection)
        self.save_btn.clicked.connect(self.save_result)
 
        # 初始化模型
        self.load_model()
 
    def load_model(self):
        try:
            model_name = self.model_combo.currentText()
            self.model = YOLOv10(f"{model_name}.pt")  # 自动下载或加载本地模型
            self.update_status(f"模型 {model_name} 加载成功")
        except Exception as e:
            QMessageBox.critical(self, "错误", f"模型加载失败: {str(e)}")
            self.update_status("模型加载失败")
 
    def detect_image(self):
        if self.detection_thread and self.detection_thread.isRunning():
            QMessageBox.warning(self, "警告", "请先停止当前检测任务")
            return
 
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择图片", "", "图片文件 (*.jpg *.jpeg *.png *.bmp)")
 
        if file_path:
            self.clear_results()
            self.current_image = cv2.imread(file_path)
            self.current_image = cv2.cvtColor(self.current_image, cv2.COLOR_BGR2RGB)
            self.display_image(self.original_image_label, self.current_image)
 
            # 创建检测线程
            conf = self.confidence_spinbox.value()
            iou = self.iou_spinbox.value()
            self.detection_thread = DetectionThread(self.model, file_path, conf, iou)
            self.detection_thread.frame_received.connect(self.on_frame_received)
            self.detection_thread.finished_signal.connect(self.on_detection_finished)
            self.detection_thread.start()
 
            self.update_status(f"正在检测图片: {os.path.basename(file_path)}")
 
    def detect_video(self):
        if self.detection_thread and self.detection_thread.isRunning():
            QMessageBox.warning(self, "警告", "请先停止当前检测任务")
            return
 
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择视频", "", "视频文件 (*.mp4 *.avi *.mov)")
 
        if file_path:
            self.clear_results()
            self.is_video_running = True
 
            # 初始化视频写入器
            cap = cv2.VideoCapture(file_path)
            frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            fps = cap.get(cv2.CAP_PROP_FPS)
            cap.release()
 
            # 创建保存路径
            save_dir = "results"
            os.makedirs(save_dir, exist_ok=True)
            timestamp = time.strftime("%Y%m%d_%H%M%S")
            save_path = os.path.join(save_dir, f"result_{timestamp}.mp4")
 
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')
            self.video_writer = cv2.VideoWriter(save_path, fourcc, fps, (frame_width, frame_height))
 
            # 创建检测线程
            conf = self.confidence_spinbox.value()
            iou = self.iou_spinbox.value()
            self.detection_thread = DetectionThread(self.model, file_path, conf, iou)
            self.detection_thread.frame_received.connect(self.on_frame_received)
            self.detection_thread.finished_signal.connect(self.on_detection_finished)
            self.detection_thread.start()
 
            self.update_status(f"正在检测视频: {os.path.basename(file_path)}")
 
    def detect_camera(self):
        if self.detection_thread and self.detection_thread.isRunning():
            QMessageBox.warning(self, "警告", "请先停止当前检测任务")
            return
 
        self.clear_results()
        self.is_camera_running = True
 
        # 创建检测线程 (默认使用摄像头0)
        conf = self.confidence_spinbox.value()
        iou = self.iou_spinbox.value()
        self.detection_thread = DetectionThread(self.model, 0, conf, iou)
        self.detection_thread.frame_received.connect(self.on_frame_received)
        self.detection_thread.finished_signal.connect(self.on_detection_finished)
        self.detection_thread.start()
 
        self.update_status("正在从摄像头检测...")
 
    def stop_detection(self):
        if self.detection_thread and self.detection_thread.isRunning():
            self.detection_thread.stop()
            self.detection_thread.quit()
            self.detection_thread.wait()
 
        if self.video_writer:
            self.video_writer.release()
            self.video_writer = None
 
        self.is_camera_running = False
        self.is_video_running = False
        self.update_status("检测已停止")
 
    def on_frame_received(self, original_frame, result_frame, detections):
        # 更新原始图像和结果图像
        self.display_image(self.original_image_label, original_frame)
        self.display_image(self.result_image_label, result_frame)
 
        # 保存当前结果帧用于后续保存
        self.last_detection_result = result_frame  # 新增:保存检测结果
 
        # 更新表格
        self.clear_results()
        for class_name, confidence, x, y in detections:
            self.add_detection_result(class_name, confidence, x, y)
 
        # 保存视频帧
        if self.video_writer:
            self.video_writer.write(cv2.cvtColor(result_frame, cv2.COLOR_RGB2BGR))
 
    def on_detection_finished(self):
        if self.video_writer:
            self.video_writer.release()
            self.video_writer = None
            self.update_status("视频检测完成,结果已保存")
        elif self.is_camera_running:
            self.update_status("摄像头检测已停止")
        else:
            self.update_status("图片检测完成")
 
    def save_result(self):
        if not hasattr(self, 'last_detection_result') or self.last_detection_result is None:
            QMessageBox.warning(self, "警告", "没有可保存的检测结果")
            return
 
        save_dir = "results"
        os.makedirs(save_dir, exist_ok=True)
        timestamp = time.strftime("%Y%m%d_%H%M%S")
 
        if self.is_camera_running or self.is_video_running:
            # 保存当前帧为图片
            save_path = os.path.join(save_dir, f"snapshot_{timestamp}.jpg")
            cv2.imwrite(save_path, cv2.cvtColor(self.last_detection_result, cv2.COLOR_RGB2BGR))
            self.update_status(f"截图已保存: {save_path}")
        else:
            # 保存图片检测结果
            save_path = os.path.join(save_dir, f"result_{timestamp}.jpg")
            cv2.imwrite(save_path, cv2.cvtColor(self.last_detection_result, cv2.COLOR_RGB2BGR))
            self.update_status(f"检测结果已保存: {save_path}")
 
    def closeEvent(self, event):
        self.stop_detection()
        event.accept()
 
 
if __name__ == "__main__":
    app = QApplication(sys.argv)
 
    # 设置应用程序样式
    app.setStyle("Fusion")
 
    # 创建并显示主窗口
    window = MainWindow()
    window.show()
 
    sys.exit(app.exec_())

七、项目源码(视频下方简介内)

        完整全部资源文件(包括测试图片、视频,py文件,训练数据集、训练代码、界面代码等),这里已打包上传至博主的面包多平台,见可参考博客与视频,已将所有涉及的文件同时打包到里面,点击即可运行,完整文件截图如下:

基于深度学习YOLOv10的苹果成熟度检测系统(YOLOv10+YOLO数据集+UI界面+Python项目源码+模型)_哔哩哔哩_bilibili

基于深度学习YOLOv10的苹果成熟度检测系统(YOLOv10+YOLO数据集+UI界面+Python项目源码+模型)

<think>好的,我现在需要帮助用户了解如何使用深度学习处理与水果相关的任务,特别是分类和检测,以及数据集的实践。首先,我需要整理用户提供的引用内容,看看里面有哪些有用的信息。 用户提到了四个引用,都是关于水果检测数据集和相关项目。比如引用[1]提到使用YOLOv5进行水果新鲜度检测数据集需要高质量且标注不同新鲜程度的水果图像。引用[2]提供了包含多种水果的数据集,适用于品质分类和成熟度检测,图像尺寸为256x256,带有边界框标注。引用[3]同样涉及YOLOv5的草莓成熟度检测,提到了Fruit Images Dataset。引用[4]是苹果缺陷数据集,适合目标检测练习,有XML标签。 用户的问题是如何使用深度学习处理水果相关的分类、检测任务,并涉及数据集实践。我需要结合这些引用内容,给出一个结构清晰的回答,包括数据集选择、模型构建、训练与评估、部署应用,以及可能的问题和解决方案。 首先,在数据集选择部分,需要提到不同任务需要的数据集类型,比如分类需要标注类别,检测需要边界框。引用中的数据集如Fruit Images Dataset和苹果缺陷数据集都可以作为例子。然后,模型构建部分,分类可以用ResNet,检测可以用YOLO,比如引用中的YOLOv5案例。训练时要预处理数据,调整超参数,并解决过拟合问题,比如数据增强。评估指标如准确率和mAP需要提到。部署方面,可以开发UI系统,如引用中的例子。最后,实践中的问题可能包括数据不足、标注质量等,解决方案如数据增强和使用预训练模型。 需要确保回答符合用户给的系统级指令,比如使用正确的中文和LaTeX格式,生成相关问题。还要检查引用是否正确标注,例如在提到数据集时加上对应的引用标识。可能还需要注意代码示例的正确性,比如YOLOv5的数据准备步骤是否正确,是否需要给出具体代码片段。 现在需要组织这些思路,确保每个部分逻辑清晰,引用适当,并且生成的相关问题与用户主题相关。可能的问题包括如何选择合适的数据集,如何优化模型性能,如何处理数据不平衡等。最终回答需要覆盖这些点,并引导用户进一步思考。</think>### 深度学习在水果分类与检测中的实践指南 #### 1. 数据集选择与预处理 深度学习任务的基础是高质量数据集。针对水果相关任务需注意: - **分类任务**:需标注水果类别(如苹果、香蕉)和属性(新鲜度、成熟度)。例如引用[2]的数据集包含多类水果图像,标注了边界框和成熟度[^2]。 - **检测任务**:需标注目标位置(边界框)和类别。例如引用[4]的苹果缺陷数据集提供XML格式的标注文件,适合目标检测训练[^4]。 - **预处理**:统一图像尺寸(如$256 \times 256$),增强数据多样性(旋转、亮度调整)。 #### 2. 模型构建与训练 ##### (1) 分类任务 - **模型选择**:轻量级任务可用ResNet、MobileNet;复杂场景可用EfficientNet。 - **损失函数**:多分类任务常用交叉熵损失: $$L = -\sum_{i=1}^C y_i \log(p_i)$$ 其中$C$为类别数,$y_i$为真实标签,$p_i$为预测概率。 ##### (2) 检测任务 - **模型选择**:YOLO系列(如YOLOv5)兼顾速度与精度。引用[1][3]展示了YOLOv5在水果成熟度检测中的应用[^1][^3]。 - **目标函数**:YOLO采用复合损失: $$L = \lambda_{\text{coord}} L_{\text{bbox}} + \lambda_{\text{obj}} L_{\text{obj}} + \lambda_{\text{cls}} L_{\text{cls}}$$ #### 3. 训练与评估 - **代码示例(YOLOv5数据准备)**: ```python from yolov5.utils.datasets import LoadImagesAndLabels dataset = LoadImagesAndLabels( path='fruit_dataset.yaml', img_size=640, batch_size=16 ) ``` - **评估指标**: - 分类:准确率($Acc = \frac{TP+TN}{TP+TN+FP+FN}$) - 检测:mAP(Mean Average Precision) #### 4. 部署与应用 - **系统集成**:如引用[1]的UI界面可将模型封装为可视化系统。 - **优化技巧**: - 使用TensorRT加速推理 - 量化技术减少模型体积 #### 常见问题与解决方案 | 问题类型 | 表现 | 解决方法 | |---------|------|---------| | 数据不足 | 过拟合严重 | 数据增强、迁移学习[^3] | | 类别不平衡 | 小样本识别差 | 重采样、Focal Loss | | 复杂背景 | 误检率高 | 改进标注质量、添加注意力模块 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人工智能_SYBH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值