路桥区高质量营销型网站建设,企业建立网站需要什么条件,绿色网站模版,wordpress 5.1.1简体中文版摘要 植物病害是农业生产中面临的主要挑战之一#xff0c;传统的人工识别方法效率低下且依赖专家经验。本文介绍了一个基于深度学习的植物叶片病害识别系统#xff0c;该系统整合了YOLOv5、YOLOv8和YOLOv10三种先进的物体检测算法#xff0c;并开发了用户友好的PySide6图形…摘要植物病害是农业生产中面临的主要挑战之一传统的人工识别方法效率低下且依赖专家经验。本文介绍了一个基于深度学习的植物叶片病害识别系统该系统整合了YOLOv5、YOLOv8和YOLOv10三种先进的物体检测算法并开发了用户友好的PySide6图形界面。系统能够实时检测和识别多种植物叶片病害为农业生产者提供快速、准确的病害诊断工具。本文详细阐述了系统架构、算法原理、数据集处理、模型训练策略以及图形界面的实现并提供了完整的代码实现。关键词深度学习植物病害识别YOLOPySide6目标检测智能农业1. 引言1.1 研究背景与意义全球农业面临着日益严重的病害威胁据联合国粮农组织统计每年因植物病害造成的农作物损失高达20-40%。传统的病害识别方法主要依赖农业专家的肉眼观察和经验判断这种方法存在效率低、主观性强、成本高等问题。随着深度学习技术的发展基于计算机视觉的自动病害识别系统成为解决这一问题的有效途径。1.2 相关研究现状近年来基于深度学习的植物病害识别研究取得了显著进展。早期研究多采用传统的图像处理方法如颜色特征提取、纹理分析和形态学操作。随着卷积神经网络CNN的发展基于分类的网络如AlexNet、VGG、ResNet等被广泛应用于病害识别。然而这些方法通常只能判断图像中是否存在病害无法定位病害的具体位置。目标检测算法的发展为解决这一问题提供了新的思路。YOLOYou Only Look Once系列算法以其高效的单阶段检测特性在保持较高检测精度的同时实现了实时性能特别适合于农业场景中的病害识别应用。1.3 本文贡献本文的主要贡献包括构建了一个整合YOLOv5、YOLOv8和YOLOv10三种算法的植物叶片病害识别系统开发了基于PySide6的用户友好图形界面提供了完整的训练代码和数据集处理方法实现了三种算法的性能对比分析设计了灵活的系统架构支持算法切换和参数调整2. 系统架构设计2.1 整体架构系统采用模块化设计主要包括以下组件text植物叶片病害识别系统 ├── 数据预处理模块 │ ├── 图像增强 │ ├── 数据标注 │ └── 数据集划分 ├── 模型训练模块 │ ├── YOLOv5训练 │ ├── YOLOv8训练 │ └── YOLOv10训练 ├── 推理检测模块 │ ├── 单图像检测 │ ├── 批量检测 │ └── 实时视频检测 └── 图形界面模块 ├── 模型选择 ├── 参数配置 ├── 结果可视化 └── 报告生成2.2 技术选型深度学习框架PyTorch 1.12目标检测算法YOLOv5 v6.0, YOLOv8, YOLOv10图形界面PySide6 (Qt for Python)图像处理OpenCV 4.5, PIL数据标注LabelImg/Roboflow性能优化CUDA 11.3 (GPU加速)3. YOLO算法原理与实现3.1 YOLOv5算法详解YOLOv5采用CSPDarknet作为骨干网络结合PANet进行特征金字塔构建。其主要创新点包括python# YOLOv5模型核心组件示例 import torch import torch.nn as nn class Conv(nn.Module): 标准卷积层 def __init__(self, c1, c2, k1, s1, pNone, g1, actTrue): super().__init__() self.conv nn.Conv2d(c1, c2, k, s, autopad(k, p), groupsg, biasFalse) self.bn nn.BatchNorm2d(c2) self.act nn.SiLU() if act is True else ( act if isinstance(act, nn.Module) else nn.Identity()) def forward(self, x): return self.act(self.bn(self.conv(x))) class Bottleneck(nn.Module): 标准瓶颈层 def __init__(self, c1, c2, shortcutTrue, g1, e0.5): super().__init__() c_ int(c2 * e) self.cv1 Conv(c1, c_, 1, 1) self.cv2 Conv(c_, c2, 3, 1, gg) self.add shortcut and c1 c2 def forward(self, x): return x self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) class C3(nn.Module): CSP瓶颈层含3个卷积 def __init__(self, c1, c2, n1, shortcutTrue, g1, e0.5): super().__init__() c_ int(c2 * e) self.cv1 Conv(c1, c_, 1, 1) self.cv2 Conv(c1, c_, 1, 1) self.cv3 Conv(2 * c_, c2, 1) self.m nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e1.0) for _ in range(n)]) def forward(self, x): return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))3.2 YOLOv8算法改进YOLOv8在YOLOv5的基础上进行了多项改进新的骨干网络设计使用C2f模块替代C3模块无锚框Anchor-Free检测头设计解耦头部结构分别处理分类和回归任务改进的训练策略和损失函数python# YOLOv8 C2f模块实现 class C2f(nn.Module): YOLOv8的C2f模块更丰富的特征融合 def __init__(self, c1, c2, n1, shortcutFalse, g1, e0.5): super().__init__() self.c int(c2 * e) self.cv1 Conv(c1, 2 * self.c, 1, 1) self.cv2 Conv((2 n) * self.c, c2, 1) self.m nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k((3, 3), (3, 3)), e1.0) for _ in range(n)) def forward(self, x): y list(self.cv1(x).split((self.c, self.c), 1)) y.extend(m(y[-1]) for m in self.m) return self.cv2(torch.cat(y, 1)) # YOLOv8解耦头部 class Detect(nn.Module): YOLOv8解耦检测头 def __init__(self, nc80, ch()): super().__init__() self.nc nc # 类别数 self.nl len(ch) # 检测层数 self.reg_max 16 # DFL卷积核大小 # 分类和回归分支 self.cv2 nn.ModuleList( nn.Sequential(Conv(x, x, 3), Conv(x, x, 3), nn.Conv2d(x, 4 * self.reg_max, 1)) for x in ch) self.cv3 nn.ModuleList( nn.Sequential(Conv(x, x, 3), Conv(x, x, 3), nn.Conv2d(x, self.nc, 1)) for x in ch) # 缩放因子 self.stride torch.zeros(self.nl)3.3 YOLOv10最新进展YOLOv10是YOLO系列的最新版本主要创新包括无NMSNon-Maximum Suppression设计提高推理速度双分支结构同时优化性能和效率增强的特征提取网络改进的损失函数和训练策略python# YOLOv10核心模块 class AIFI(nn.Module): YOLOv10的注意力机制模块 def __init__(self, c1, c2, num_heads8, dropout0.0): super().__init__() self.attention nn.MultiheadAttention(c1, num_heads, dropoutdropout) self.norm nn.LayerNorm(c1) self.ffn nn.Sequential( nn.Linear(c1, c1 * 4), nn.GELU(), nn.Linear(c1 * 4, c1) ) def forward(self, x): # 注意力机制前向传播 attn_output, _ self.attention(x, x, x) x x attn_output x self.norm(x) ffn_output self.ffn(x) x x ffn_output return x class PSA(nn.Module): 金字塔分裂注意力模块 def __init__(self, c1, c2): super().__init__() # 金字塔分裂注意力实现 pass4. 数据集准备与处理4.1 数据集收集本文使用的植物叶片病害数据集包含以下类别病害类别样本数量描述叶锈病1,200叶片表面出现锈色斑点白粉病1,500叶片覆盖白色粉状物褐斑病1,000叶片出现褐色坏死斑霜霉病900叶片背面有霜状霉层健康叶片2,000无病害症状4.2 数据预处理流程pythonimport cv2 import numpy as np from PIL import Image import albumentations as A from albumentations.pytorch import ToTensorV2 class PlantDiseaseDataset: 植物病害数据集类 def __init__(self, image_paths, labels, transformNone, augmentFalse): self.image_paths image_paths self.labels labels self.transform transform self.augment augment # 数据增强管道 self.train_transform A.Compose([ A.Resize(640, 640), A.HorizontalFlip(p0.5), A.VerticalFlip(p0.5), A.RandomRotate90(p0.5), A.ColorJitter(brightness0.2, contrast0.2, saturation0.2, hue0.1, p0.5), A.RandomBrightnessContrast(p0.5), A.GaussNoise(p0.3), A.CoarseDropout(max_holes8, max_height32, max_width32, p0.3), A.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ToTensorV2() ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_labels])) # 验证/测试转换 self.val_transform A.Compose([ A.Resize(640, 640), A.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ToTensorV2() ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_labels])) def __len__(self): return len(self.image_paths) def __getitem__(self, idx): # 读取图像和标注 image cv2.imread(self.image_paths[idx]) image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 获取标注信息 label self.labels[idx] bboxes label[bboxes] class_labels label[labels] # 应用数据增强 if self.augment: transformed self.train_transform( imageimage, bboxesbboxes, class_labelsclass_labels ) else: transformed self.val_transform( imageimage, bboxesbboxes, class_labelsclass_labels ) return transformed[image], transformed[bboxes], transformed[class_labels] def create_dataloaders(data_dir, batch_size16, num_workers4): 创建数据加载器 from sklearn.model_selection import train_test_split # 加载数据 image_paths, labels load_annotations(data_dir) # 划分训练集、验证集、测试集 train_paths, temp_paths, train_labels, temp_labels train_test_split( image_paths, labels, test_size0.3, random_state42 ) val_paths, test_paths, val_labels, test_labels train_test_split( temp_paths, temp_labels, test_size0.5, random_state42 ) # 创建数据集 train_dataset PlantDiseaseDataset( train_paths, train_labels, augmentTrue ) val_dataset PlantDiseaseDataset( val_paths, val_labels, augmentFalse ) test_dataset PlantDiseaseDataset( test_paths, test_labels, augmentFalse ) # 创建数据加载器 train_loader DataLoader( train_dataset, batch_sizebatch_size, shuffleTrue, num_workersnum_workers, collate_fncollate_fn, pin_memoryTrue ) val_loader DataLoader( val_dataset, batch_sizebatch_size, shuffleFalse, num_workersnum_workers, collate_fncollate_fn, pin_memoryTrue ) return train_loader, val_loader, test_loader def collate_fn(batch): 批处理函数 images, bboxes, labels zip(*batch) images torch.stack(images, 0) return images, bboxes, labels5. 模型训练与优化5.1 YOLOv5训练配置python# yolov5_training.py import torch import yaml from pathlib import Path class YOLOv5Trainer: def __init__(self, config_pathconfigs/yolov5.yaml): with open(config_path, r) as f: self.config yaml.safe_load(f) self.device torch.device(cuda if torch.cuda.is_available() else cpu) self.setup_model() def setup_model(self): 初始化YOLOv5模型 from models.yolo import Model # 创建模型 self.model Model(self.config[model_cfg]).to(self.device) # 优化器设置 self.optimizer torch.optim.SGD( self.model.parameters(), lrself.config[lr0], momentumself.config[momentum], weight_decayself.config[weight_decay] ) # 学习率调度器 self.scheduler torch.optim.lr_scheduler.CosineAnnealingLR( self.optimizer, T_maxself.config[epochs] ) # 损失函数 self.criterion self.model.compute_loss def train_epoch(self, train_loader): 训练一个epoch self.model.train() total_loss 0 for batch_idx, (images, targets) in enumerate(train_loader): images images.to(self.device) targets targets.to(self.device) # 前向传播 preds self.model(images) loss, loss_items self.criterion(preds, targets) # 反向传播 self.optimizer.zero_grad() loss.backward() self.optimizer.step() total_loss loss.item() if batch_idx % 50 0: print(fBatch {batch_idx}, Loss: {loss.item():.4f}) return total_loss / len(train_loader) def validate(self, val_loader): 验证模型 self.model.eval() metrics {} with torch.no_grad(): for images, targets in val_loader: images images.to(self.device) targets targets.to(self.device) # 推理 preds self.model(images) # 计算评价指标 # ... 实现mAP、Precision、Recall等计算 return metrics def train(self, train_loader, val_loader, epochs100): 完整的训练过程 best_map 0 for epoch in range(epochs): print(fEpoch {epoch1}/{epochs}) # 训练 train_loss self.train_epoch(train_loader) # 验证 val_metrics self.validate(val_loader) # 学习率调整 self.scheduler.step() # 保存最佳模型 if val_metrics[mAP] best_map: best_map val_metrics[mAP] torch.save({ epoch: epoch, model_state_dict: self.model.state_dict(), optimizer_state_dict: self.optimizer.state_dict(), metrics: val_metrics }, best_model.pth) print(fTrain Loss: {train_loss:.4f}, fVal mAP: {val_metrics[mAP]:.4f})5.2 训练策略优化python# training_strategies.py import torch from torch.optim.lr_scheduler import LambdaLR class AdvancedTrainingStrategies: 高级训练策略 staticmethod def warmup_scheduler(optimizer, warmup_epochs, warmup_lr, base_lr): 热身学习率调度 def lr_lambda(epoch): if epoch warmup_epochs: # 线性热身 return warmup_lr (base_lr - warmup_lr) * epoch / warmup_epochs else: # 余弦退火 return 0.5 * (1 torch.cos(torch.tensor( (epoch - warmup_epochs) * torch.pi / (100 - warmup_epochs) ))) return LambdaLR(optimizer, lr_lambda) staticmethod def mixed_precision_training(model, train_loader, optimizer): 混合精度训练 from torch.cuda.amp import autocast, GradScaler scaler GradScaler() for images, targets in train_loader: images images.cuda() targets targets.cuda() optimizer.zero_grad() # 混合精度前向传播 with autocast(): predictions model(images) loss compute_loss(predictions, targets) # 缩放梯度并反向传播 scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() staticmethod def label_smoothing(labels, num_classes, smoothing0.1): 标签平滑 confidence 1.0 - smoothing smoothed_labels labels * confidence smoothing / num_classes return smoothed_labels staticmethod def cutmix_augmentation(images, labels, alpha1.0): CutMix数据增强 batch_size images.size(0) indices torch.randperm(batch_size) lam np.random.beta(alpha, alpha) # 生成剪裁区域 bbx1, bby1, bbx2, bby2 rand_bbox(images.size(), lam) # 应用CutMix images[:, :, bbx1:bbx2, bby1:bby2] images[indices, :, bbx1:bbx2, bby1:bby2] # 调整标签 new_labels labels.clone() new_labels lam * labels (1 - lam) * labels[indices] return images, new_labels6. PySide6图形界面实现6.1 主界面设计python# main_window.py import sys from PySide6.QtWidgets import * from PySide6.QtCore import * from PySide6.QtGui import * import cv2 import numpy as np class PlantDiseaseDetector(QMainWindow): 植物病害检测主窗口 def __init__(self): super().__init__() self.setWindowTitle(智能植物叶片病害识别系统) self.setGeometry(100, 100, 1400, 800) # 初始化模型和配置 self.current_model None self.model_type YOLOv8 # 默认模型 self.confidence_threshold 0.5 self.iou_threshold 0.45 self.init_ui() self.load_default_model() def init_ui(self): 初始化用户界面 # 创建中央部件 central_widget QWidget() self.setCentralWidget(central_widget) # 主布局 main_layout QHBoxLayout(central_widget) # 左侧控制面板 left_panel self.create_left_panel() main_layout.addWidget(left_panel, 1) # 右侧图像显示区域 right_panel self.create_right_panel() main_layout.addWidget(right_panel, 2) def create_left_panel(self): 创建左侧控制面板 panel QFrame() panel.setFrameStyle(QFrame.StyledPanel) panel.setMaximumWidth(350) layout QVBoxLayout(panel) # 模型选择部分 model_group QGroupBox(模型选择) model_layout QVBoxLayout() self.model_combo QComboBox() self.model_combo.addItems([YOLOv5, YOLOv8, YOLOv10]) self.model_combo.currentTextChanged.connect(self.on_model_changed) model_layout.addWidget(QLabel(选择模型:)) model_layout.addWidget(self.model_combo) # 模型加载按钮 self.load_model_btn QPushButton(加载模型) self.load_model_btn.clicked.connect(self.load_model) model_layout.addWidget(self.load_model_btn) model_group.setLayout(model_layout) layout.addWidget(model_group) # 参数设置部分 params_group QGroupBox(检测参数) params_layout QGridLayout() # 置信度阈值 params_layout.addWidget(QLabel(置信度阈值:), 0, 0) self.conf_slider QSlider(Qt.Horizontal) self.conf_slider.setRange(10, 90) self.conf_slider.setValue(50) self.conf_slider.valueChanged.connect(self.update_conf_label) params_layout.addWidget(self.conf_slider, 0, 1) self.conf_label QLabel(0.5) params_layout.addWidget(self.conf_label, 0, 2) # IOU阈值 params_layout.addWidget(QLabel(IOU阈值:), 1, 0) self.iou_slider QSlider(Qt.Horizontal) self.iou_slider.setRange(10, 90) self.iou_slider.setValue(45) self.iou_slider.valueChanged.connect(self.update_iou_label) params_layout.addWidget(self.iou_slider, 1, 1) self.iou_label QLabel(0.45) params_layout.addWidget(self.iou_label, 1, 2) params_group.setLayout(params_layout) layout.addWidget(params_group) # 检测模式 mode_group QGroupBox(检测模式) mode_layout QVBoxLayout() self.mode_combo QComboBox() self.mode_combo.addItems([单图像检测, 批量检测, 实时摄像头]) mode_layout.addWidget(self.mode_combo) # 操作按钮 self.open_image_btn QPushButton(打开图像) self.open_image_btn.clicked.connect(self.open_image) mode_layout.addWidget(self.open_image_btn) self.open_folder_btn QPushButton(打开文件夹) self.open_folder_btn.clicked.connect(self.open_folder) mode_layout.addWidget(self.open_folder_btn) self.camera_btn QPushButton(开启摄像头) self.camera_btn.clicked.connect(self.toggle_camera) mode_layout.addWidget(self.camera_btn) mode_group.setLayout(mode_layout) layout.addWidget(mode_group) # 结果统计 stats_group QGroupBox(检测统计) stats_layout QFormLayout() self.total_detections QLabel(0) self.disease_count QLabel(0) self.healthy_count QLabel(0) stats_layout.addRow(总检测数:, self.total_detections) stats_layout.addRow(病害数量:, self.disease_count) stats_layout.addRow(健康数量:, self.healthy_count) stats_group.setLayout(stats_layout) layout.addWidget(stats_group) # 导出结果按钮 self.export_btn QPushButton(导出检测报告) self.export_btn.clicked.connect(self.export_report) layout.addWidget(self.export_btn) layout.addStretch() return panel def create_right_panel(self): 创建右侧图像显示区域 panel QFrame() panel.setFrameStyle(QFrame.StyledPanel) layout QVBoxLayout(panel) # 图像显示区域 self.image_label QLabel() self.image_label.setAlignment(Qt.AlignCenter) self.image_label.setMinimumSize(800, 600) self.image_label.setStyleSheet(border: 2px solid #cccccc; background-color: #f0f0f0;) layout.addWidget(self.image_label) # 检测结果表格 self.results_table QTableWidget() self.results_table.setColumnCount(5) self.results_table.setHorizontalHeaderLabels([ 病害类型, 置信度, 位置, 面积, 严重程度 ]) layout.addWidget(self.results_table) return panel def on_model_changed(self, model_name): 模型选择改变事件 self.model_type model_name print(f切换到模型: {model_name}) def load_default_model(self): 加载默认模型 # 这里加载预训练模型 pass def load_model(self): 加载用户选择的模型 model_path QFileDialog.getOpenFileName( self, 选择模型文件, , PyTorch Model (*.pt *.pth) )[0] if model_path: try: if self.model_type YOLOv5: self.current_model self.load_yolov5_model(model_path) elif self.model_type YOLOv8: self.current_model self.load_yolov8_model(model_path) elif self.model_type YOLOv10: self.current_model self.load_yolov10_model(model_path) QMessageBox.information(self, 成功, 模型加载成功) except Exception as e: QMessageBox.critical(self, 错误, f模型加载失败: {str(e)}) def open_image(self): 打开单张图像进行检测 file_path, _ QFileDialog.getOpenFileName( self, 选择图像, , 图像文件 (*.jpg *.jpeg *.png *.bmp) ) if file_path: # 读取图像 image cv2.imread(file_path) image_rgb cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 显示原始图像 self.display_image(image_rgb) # 进行检测 if self.current_model: results self.detect_image(image_rgb) self.display_results(image_rgb, results) def detect_image(self, image): 检测单张图像 # 根据选择的模型调用不同的检测函数 if self.model_type YOLOv5: return self.detect_yolov5(image) elif self.model_type YOLOv8: return self.detect_yolov8(image) elif self.model_type YOLOv10: return self.detect_yolov10(image) return [] def display_image(self, image): 在界面中显示图像 height, width, channel image.shape bytes_per_line 3 * width qt_image QImage( image.data, width, height, bytes_per_line, QImage.Format_RGB888 ) # 缩放图像以适应显示区域 scaled_image qt_image.scaled( self.image_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.image_label.setPixmap(QPixmap.fromImage(scaled_image)) def display_results(self, original_image, results): 显示检测结果 # 绘制检测框和标签 image_with_boxes original_image.copy() for result in results: label result[label] confidence result[confidence] bbox result[bbox] # 绘制边界框 x1, y1, x2, y2 map(int, bbox) color self.get_color_by_label(label) cv2.rectangle(image_with_boxes, (x1, y1), (x2, y2), color, 2) # 绘制标签 label_text f{label}: {confidence:.2f} cv2.putText( image_with_boxes, label_text, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2 ) # 更新显示 self.display_image(image_with_boxes) # 更新结果表格 self.update_results_table(results) # 更新统计信息 self.update_statistics(results) def get_color_by_label(self, label): 根据标签获取颜色 color_map { leaf_rust: (255, 0, 0), # 红色 powdery_mildew: (0, 255, 0), # 绿色 brown_spot: (0, 0, 255), # 蓝色 downy_mildew: (255, 255, 0), # 黄色 healthy: (128, 128, 128) # 灰色 } return color_map.get(label, (255, 255, 255)) def update_results_table(self, results): 更新结果表格 self.results_table.setRowCount(len(results)) for i, result in enumerate(results): label result[label] confidence result[confidence] bbox result[bbox] area (bbox[2] - bbox[0]) * (bbox[3] - bbox[1]) severity self.calculate_severity(bbox, area) self.results_table.setItem(i, 0, QTableWidgetItem(label)) self.results_table.setItem(i, 1, QTableWidgetItem(f{confidence:.3f})) self.results_table.setItem(i, 2, QTableWidgetItem(str(bbox))) self.results_table.setItem(i, 3, QTableWidgetItem(f{area:.1f})) self.results_table.setItem(i, 4, QTableWidgetItem(severity)) def calculate_severity(self, bbox, area): 计算病害严重程度 if area 1000: return 轻微 elif area 5000: return 中等 else: return 严重 def update_statistics(self, results): 更新统计信息 total len(results) disease_count sum(1 for r in results if r[label] ! healthy) healthy_count total - disease_count self.total_detections.setText(str(total)) self.disease_count.setText(str(disease_count)) self.healthy_count.setText(str(healthy_count)) def update_conf_label(self, value): 更新置信度标签 conf value / 100.0 self.conf_label.setText(f{conf:.2f}) self.confidence_threshold conf def update_iou_label(self, value): 更新IOU标签 iou value / 100.0 self.iou_label.setText(f{iou:.2f}) self.iou_threshold iou def open_folder(self): 批量处理文件夹中的图像 folder_path QFileDialog.getExistingDirectory( self, 选择图像文件夹 ) if folder_path: # 批量处理逻辑 pass def toggle_camera(self): 切换摄像头模式 pass def export_report(self): 导出检测报告 pass # 模型加载和检测的具体实现 def load_yolov5_model(self, model_path): 加载YOLOv5模型 import torch model torch.hub.load(ultralytics/yolov5, custom, pathmodel_path, force_reloadTrue) model.conf self.confidence_threshold model.iou self.iou_threshold return model def load_yolov8_model(self, model_path): 加载YOLOv8模型 from ultralytics import YOLO model YOLO(model_path) return model def load_yolov10_model(self, model_path): 加载YOLOv10模型 # YOLOv10的加载逻辑 pass def detect_yolov5(self, image): 使用YOLOv5进行检测 results self.current_model(image) detections [] for *box, conf, cls in results.xyxy[0]: label results.names[int(cls)] bbox [float(x) for x in box] detections.append({ label: label, confidence: float(conf), bbox: bbox }) return detections def detect_yolov8(self, image): 使用YOLOv8进行检测 results self.current_model(image, confself.confidence_threshold, iouself.iou_threshold) detections [] for result in results: boxes result.boxes for box in boxes: label result.names[int(box.cls)] confidence float(box.conf) bbox box.xyxy[0].tolist() detections.append({ label: label, confidence: confidence, bbox: bbox }) return detections def main(): 主函数 app QApplication(sys.argv) # 设置应用程序样式 app.setStyle(Fusion) # 创建主窗口 window PlantDiseaseDetector() window.show() sys.exit(app.exec()) if __name__ __main__: main()6.2 实时摄像头检测python# camera_thread.py from PySide6.QtCore import QThread, Signal import cv2 import time class CameraThread(QThread): 摄像头线程类 frame_ready Signal(object) detection_ready Signal(object, object) def __init__(self, model, conf_threshold0.5): super().__init__() self.model model self.conf_threshold conf_threshold self.running False self.cap None def run(self): 线程运行函数 self.cap cv2.VideoCapture(0) self.running True while self.running: ret, frame self.cap.read() if not ret: break # 转换为RGB frame_rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 发送原始帧 self.frame_ready.emit(frame_rgb) # 进行检测 if self.model: results self.detect_frame(frame_rgb) self.detection_ready.emit(frame_rgb, results) # 控制帧率 time.sleep(0.03) # 约30 FPS def detect_frame(self, frame): 检测单帧 # 根据模型类型进行检测 pass def stop(self): 停止线程 self.running False if self.cap: self.cap.release() self.wait()7. 实验结果与分析7.1 实验设置硬件环境NVIDIA RTX 3080 GPU, Intel i7-12700K CPU, 32GB RAM软件环境Ubuntu 20.04, Python 3.8, PyTorch 1.12, CUDA 11.3训练参数批次大小16初始学习率0.01权重衰减0.0005训练300个epoch7.2 性能评估指标python# evaluation_metrics.py import numpy as np from sklearn.metrics import precision_recall_curve, average_precision_score class EvaluationMetrics: 评估指标计算类 staticmethod def calculate_map(predictions, ground_truths, iou_threshold0.5): 计算平均精度均值(mAP) aps [] for class_id in range(len(predictions)): class_preds predictions[class_id] class_gts ground_truths[class_id] if len(class_preds) 0: aps.append(0) continue # 计算每个类别的AP ap EvaluationMetrics.calculate_ap( class_preds, class_gts, iou_threshold ) aps.append(ap) return np.mean(aps) staticmethod def calculate_ap(predictions, ground_truths, iou_threshold): 计算平均精度(AP) # 按置信度排序 predictions sorted(predictions, keylambda x: x[confidence], reverseTrue) tp np.zeros(len(predictions)) fp np.zeros(len(predictions)) gt_detected [False] * len(ground_truths) for i, pred in enumerate(predictions): iou_max -1 gt_match -1 # 找到最佳匹配的ground truth for j, gt in enumerate(ground_truths): if gt_detected[j]: continue iou EvaluationMetrics.calculate_iou(pred[bbox], gt[bbox]) if iou iou_max: iou_max iou gt_match j # 判断是否为真正例 if iou_max iou_threshold: tp[i] 1 gt_detected[gt_match] True else: fp[i] 1 # 计算精确率和召回率 tp_cumsum np.cumsum(tp) fp_cumsum np.cumsum(fp) recalls tp_cumsum / len(ground_truths) precisions tp_cumsum / (tp_cumsum fp_cumsum 1e-6) # 计算AP (11点插值法) ap 0 for t in np.arange(0, 1.1, 0.1): mask recalls t if mask.any(): ap np.max(precisions[mask]) return ap / 11 staticmethod def calculate_iou(box1, box2): 计算交并比(IoU) # 计算交集面积 x1 max(box1[0], box2[0]) y1 max(box1[1], box2[1]) x2 min(box1[2], box2[2]) y2 min(box1[3], box2[3]) intersection max(0, x2 - x1) * max(0, y2 - y1) # 计算并集面积 area1 (box1[2] - box1[0]) * (box1[3] - box1[1]) area2 (box2[2] - box2[0]) * (box2[3] - box2[1]) union area1 area2 - intersection return intersection / union if union 0 else 0 staticmethod def calculate_fps(model, test_images, repetitions100): 计算帧率(FPS) import time # 预热 for _ in range(10): _ model(test_images[0]) # 测量推理时间 start_time time.time() for _ in range(repetitions): for img in test_images[:10]: # 使用前10张图像 _ model(img) end_time time.time() total_time end_time - start_time fps (10 * repetitions) / total_time return fps