
在实际海洋生态监测和水产养殖项目中传统的人工水下调查方式不仅成本高昂、效率低下还面临安全风险。基于深度学习的计算机视觉技术为水下生物识别提供了新的解决方案而 YOLOv8 作为当前最先进的目标检测框架之一在实时性和准确性方面表现出色。本文将详细介绍如何从零构建一个完整的 YOLOv8 水下生物识别检测系统能够准确识别海胆、海参、扇贝、海星和水草五类目标并提供完整的项目源码、数据集和模型权重。这个系统特别针对水下图像的光线散射、颜色失真、低对比度等挑战进行了优化支持图片检测、视频检测和摄像头实时检测三种模式并配备了直观的 PyQt5 图形界面。无论你是从事海洋研究的科研人员、水产养殖的技术工程师还是想要学习 YOLOv8 实战应用的开发者都能通过本文掌握完整的技术实现路径。1. 理解 YOLOv8 在水下生物检测中的技术优势1.1 为什么选择 YOLOv8 而不是传统图像处理方法水下生物检测面临的核心挑战在于图像质量的严重退化。传统基于颜色阈值、边缘检测或模板匹配的方法在水下环境中往往失效主要原因包括颜色失真水体对不同波长光线的吸收程度不同导致红色和黄色波段严重衰减图像整体呈现蓝绿色调雾化效应水中悬浮颗粒造成的光线散射使图像对比度降低细节模糊光照不均自然光在水下的穿透深度有限加上人工光源的局部照射形成强烈的明暗反差动态模糊水流运动和水生生物的活动导致拍摄图像模糊YOLOv8 通过端到端的深度学习方式能够从大量样本中学习到这些退化因素的不变特征。与两阶段检测器相比YOLOv8 的单阶段设计在保持高精度的同时实现了更快的推理速度这对于需要实时反馈的水下监测场景至关重要。1.2 YOLOv8 模型家族的选型考量YOLOv8 提供了从 Nano 到 Extra-Large 的多种规模模型针对水下生物检测的具体需求选型时需要权衡以下因素模型规格参数量适用场景水下检测建议YOLOv8n~3.2M嵌入式设备、移动端适合算力受限的水下机器人YOLOv8s~11.2M实时检测、边缘计算推荐用于大部分水下监测场景YOLOv8m~25.9M平衡速度与精度适合固定式高清监控设备YOLOv8l~43.7M高精度检测用于科研级图像分析YOLOv8x~68.2M极致精度需求计算资源充足的研究环境对于一般的水下生物检测项目YOLOv8s 在精度和速度之间提供了最佳平衡。如果部署在算力受限的水下机器人上可以考虑 YOLOv8n而对精度要求极高的科研应用YOLOv8l 或 YOLOv8x 更为合适。1.3 水下生物检测的特殊技术考量与常规目标检测相比水下生物检测需要特别关注以下几个方面小目标检测许多水下生物在图像中占比较小需要调整模型锚框尺寸和特征金字塔设计遮挡处理水草遮挡、生物间重叠是常见现象模型需要具备较强的部分遮挡识别能力多尺度适应性不同拍摄距离和镜头焦距导致的目标尺度变化需要模型具备多尺度检测能力类别不平衡某些稀有物种的样本数量可能远少于常见物种需要采用合适的采样策略2. 项目环境配置与依赖管理2.1 创建专用的 Python 虚拟环境为每个深度学习项目创建独立的虚拟环境是避免依赖冲突的最佳实践。推荐使用 Anaconda 进行环境管理# 创建 Python 3.9 虚拟环境 conda create -n yolov8_underwater python3.9 # 激活环境 conda activate yolov8_underwater选择 Python 3.9 的原因是它在稳定性与最新特性支持之间取得了良好平衡且与主要深度学习框架的兼容性经过充分验证。2.2 安装 PyTorch 及相关依赖根据硬件配置选择合适的 PyTorch 版本。如果使用 NVIDIA GPU需要先确认 CUDA 版本# 查看 CUDA 版本 nvidia-smi # 安装对应版本的 PyTorch以 CUDA 11.8 为例 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118如果没有 GPU 或 CUDA 不可用安装 CPU 版本pip install torch torchvision torchaudio2.3 安装项目特定依赖创建requirements.txt文件包含项目所需的所有依赖ultralytics8.0.196 opencv-python4.8.1.78 PyQt55.15.9 numpy1.24.3 pillow10.0.0 scipy1.11.3 matplotlib3.7.2 seaborn0.12.2 pandas2.0.3 albumentations1.3.1 tqdm4.65.0安装依赖包pip install -r requirements.txt2.4 验证环境配置创建验证脚本env_check.py确认环境配置正确import torch import cv2 from PyQt5.QtWidgets import QApplication import sys def check_environment(): print( 环境配置验证 ) # 检查 PyTorch print(fPyTorch 版本: {torch.__version__}) print(fCUDA 可用: {torch.cuda.is_available()}) if torch.cuda.is_available(): print(fGPU 设备: {torch.cuda.get_device_name(0)}) # 检查 OpenCV print(fOpenCV 版本: {cv2.__version__}) # 检查 PyQt5 app QApplication(sys.argv) print(PyQt5 环境正常) print( 环境验证完成 ) if __name__ __main__: check_environment()运行验证脚本确保所有关键依赖正常工作。3. 水下生物数据集准备与处理3.1 数据集结构与标注规范本项目使用的数据集包含 7600 张高质量水下图像按照 7:2:1 的比例划分为训练集、验证集和测试集。数据集采用 YOLO 格式目录结构如下underwater_dataset/ ├── images/ │ ├── train/ # 5320 张训练图像 │ ├── val/ # 1520 张验证图像 │ └── test/ # 760 张测试图像 └── labels/ ├── train/ # 对应的训练标注文件 ├── val/ # 验证标注文件 └── test/ # 测试标注文件每个标注文件为.txt格式每行表示一个检测目标class_id x_center y_center width height其中坐标值均为归一化后的相对值0-1 之间。3.2 数据集配置文件创建data.yaml配置文件定义数据集路径和类别信息# 数据集路径 path: /path/to/underwater_dataset # 数据集根目录 train: images/train # 训练集相对路径 val: images/val # 验证集相对路径 test: images/test # 测试集相对路径 # 类别数量 nc: 5 # 类别名称 names: 0: echinus # 海胆 1: holothurian # 海参 2: scallop # 扇贝 3: starfish # 海星 4: waterweeds # 水草3.3 数据增强策略针对水下环境优化水下图像的特殊性要求定制化的数据增强策略。在train.py中配置针对性的增强参数from ultralytics import YOLO import albumentations as A from albumentations.pytorch import ToTensorV2 def get_underwater_augmentations(): 针对水下环境的增强策略 return A.Compose([ # 颜色校正类增强 A.RandomGamma(gamma_limit(80, 120), p0.5), # 模拟不同水质能见度 A.HueSaturationValue(hue_shift_limit20, sat_shift_limit30, val_shift_limit20, p0.5), A.CLAHE(clip_limit2.0, tile_grid_size(8, 8), p0.3), # 增强对比度 # 光学效应模拟 A.GaussNoise(var_limit(10.0, 50.0), p0.3), # 模拟水下颗粒噪声 A.MotionBlur(blur_limit7, p0.2), # 模拟水流运动模糊 # 几何变换 A.Rotate(limit15, p0.5), A.RandomScale(scale_limit0.2, p0.5), A.HorizontalFlip(p0.5), # 遮挡模拟 A.CoarseDropout(max_holes8, max_height20, max_width20, p0.3), ToTensorV2() ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_labels]))3.4 数据集质量检查创建数据质量检查脚本确保标注准确性和数据一致性import os import cv2 import yaml from pathlib import Path def validate_dataset(data_yaml_path): 验证数据集完整性 with open(data_yaml_path, r) as f: data_cfg yaml.safe_load(f) base_path Path(data_cfg[path]) issues [] for split in [train, val, test]: image_dir base_path / data_cfg[split] label_dir base_path / labels / split if not image_dir.exists(): issues.append(f图像目录不存在: {image_dir}) continue if not label_dir.exists(): issues.append(f标注目录不存在: {label_dir}) continue # 检查图像和标注文件对应关系 image_files list(image_dir.glob(*.jpg)) list(image_dir.glob(*.png)) for img_path in image_files: label_path label_dir / f{img_path.stem}.txt if not label_path.exists(): issues.append(f标注文件缺失: {label_path}) return issues # 运行检查 if __name__ __main__: issues validate_dataset(data.yaml) if issues: print(发现以下问题:) for issue in issues: print(f- {issue}) else: print(数据集验证通过)4. YOLOv8 模型训练与优化4.1 模型训练配置创建训练脚本train.py配置训练参数from ultralytics import YOLO import os def train_model(): # 加载预训练模型 model YOLO(yolov8s.pt) # 使用小模型平衡速度与精度 # 训练参数配置 results model.train( datadata.yaml, # 数据集配置文件 epochs500, # 训练轮数 batch16, # 批次大小根据GPU内存调整 imgsz640, # 输入图像尺寸 device0, # 使用GPU 0 workers4, # 数据加载线程数 patience50, # 早停耐心值 lr00.01, # 初始学习率 lrf0.01, # 最终学习率 momentum0.937, # 动量 weight_decay0.0005, # 权重衰减 warmup_epochs3.0, # 热身轮数 warmup_momentum0.8, # 热身动量 box7.5, # 框损失权重 cls0.5, # 分类损失权重 dfl1.5, # 分布焦点损失权重 saveTrue, # 保存检查点 exist_okTrue, # 覆盖现有输出 pretrainedTrue, # 使用预训练权重 optimizerauto, # 自动选择优化器 verboseTrue, # 输出详细信息 seed42, # 随机种子 deterministicTrue, # 确定性训练 single_clsFalse, # 多类别检测 rectFalse, # 矩形训练 cos_lrTrue, # 余弦学习率调度 close_mosaic10, # 最后10轮关闭马赛克增强 resumeFalse, # 不从检查点恢复 ampTrue, # 自动混合精度 fraction1.0 # 使用全部数据 ) return results if __name__ __main__: # 开始训练 print(开始训练 YOLOv8 水下生物检测模型...) results train_model() print(训练完成)4.2 训练过程监控与调优训练过程中需要密切关注以下指标损失函数变化确保训练损失和验证损失同步下降精度指标关注 mAP0.5 和 mAP0.5:0.95 的提升学习率调整观察学习率自动调整是否合理创建训练监控脚本import matplotlib.pyplot as plt import pandas as pd from pathlib import Path def analyze_training_results(runs_dirruns/detect): 分析训练结果 results_dir Path(runs_dir) exp_dirs [d for d in results_dir.iterdir() if d.is_dir() and d.name.startswith(train)] if not exp_dirs: print(未找到训练结果) return latest_exp max(exp_dirs, keylambda x: x.stat().st_mtime) results_file latest_exp / results.csv if results_file.exists(): df pd.read_csv(results_file) # 绘制损失曲线 plt.figure(figsize(15, 10)) # 损失子图 plt.subplot(2, 3, 1) plt.plot(df[epoch], df[train/box_loss], label训练框损失) plt.plot(df[epoch], df[val/box_loss], label验证框损失) plt.title(边界框损失) plt.legend() plt.subplot(2, 3, 2) plt.plot(df[epoch], df[train/cls_loss], label训练分类损失) plt.plot(df[epoch], df[val/cls_loss], label验证分类损失) plt.title(分类损失) plt.legend() plt.subplot(2, 3, 3) plt.plot(df[epoch], df[train/dfl_loss], label训练DFL损失) plt.plot(df[epoch], df[val/dfl_loss], label验证DFL损失) plt.title(DFL损失) plt.legend() # 精度子图 plt.subplot(2, 3, 4) plt.plot(df[epoch], df[metrics/precision(B)], label精确率) plt.title(精确率) plt.legend() plt.subplot(2, 3, 5) plt.plot(df[epoch], df[metrics/recall(B)], label召回率) plt.title(召回率) plt.legend() plt.subplot(2, 3, 6) plt.plot(df[epoch], df[metrics/mAP50(B)], labelmAP0.5) plt.plot(df[epoch], df[metrics/mAP50-95(B)], labelmAP0.5:0.95) plt.title(mAP指标) plt.legend() plt.tight_layout() plt.savefig(training_analysis.png, dpi300, bbox_inchestight) plt.show() # 输出最终指标 final_metrics df.iloc[-1] print(f最终训练结果:) print(fmAP0.5: {final_metrics[metrics/mAP50(B)]:.3f}) print(fmAP0.5:0.95: {final_metrics[metrics/mAP50-95(B)]:.3f}) print(f精确率: {final_metrics[metrics/precision(B)]:.3f}) print(f召回率: {final_metrics[metrics/recall(B)]:.3f}) if __name__ __main__: analyze_training_results()4.3 模型导出与优化训练完成后将模型导出为适合部署的格式from ultralytics import YOLO def export_model(): # 加载最佳模型 model YOLO(runs/detect/train/weights/best.pt) # 导出为不同格式 export_formats [ onnx, # ONNX格式通用推理 engine, # TensorRT引擎NVIDIA GPU加速 openvino, # OpenVINO格式Intel硬件加速 torchscript # TorchScriptPyTorch原生部署 ] for fmt in export_formats: try: model.export(formatfmt, imgsz640, optimizeTrue) print(f成功导出为 {fmt.upper()} 格式) except Exception as e: print(f导出 {fmt} 失败: {e}) if __name__ __main__: export_model()5. 图形界面开发与功能集成5.1 PyQt5 界面设计与布局创建主界面类实现检测系统的核心功能import sys import os import cv2 import numpy as np from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QGroupBox, QLabel, QPushButton, QSlider, QComboBox, QFileDialog, QMessageBox, QTableWidget, QTableWidgetItem, QHeaderView, QStatusBar, QProgressBar) from PyQt5.QtCore import Qt, QTimer, pyqtSignal, QThread from PyQt5.QtGui import QImage, QPixmap, QIcon, QFont from ultralytics import YOLO import datetime class DetectionThread(QThread): 检测线程避免界面卡顿 finished pyqtSignal(object) error pyqtSignal(str) def __init__(self, model, image, conf_threshold, iou_threshold): super().__init__() self.model model self.image image self.conf_threshold conf_threshold self.iou_threshold iou_threshold def run(self): try: results self.model.predict( self.image, confself.conf_threshold, iouself.iou_threshold, verboseFalse ) self.finished.emit(results) except Exception as e: self.error.emit(str(e)) class UnderwaterDetectionUI(QMainWindow): def __init__(self): super().__init__() self.model None self.current_image None self.current_results None self.cap None self.timer QTimer() self.is_detecting False self.detection_thread None self.init_ui() self.setup_connections() def init_ui(self): self.setWindowTitle(YOLOv8 水下生物识别检测系统) self.setGeometry(100, 100, 1600, 900) # 设置窗口图标 self.setWindowIcon(QIcon(icon.ico) if os.path.exists(icon.ico) else QIcon()) # 创建中央部件 central_widget QWidget() self.setCentralWidget(central_widget) # 主布局 main_layout QHBoxLayout(central_widget) main_layout.setContentsMargins(10, 10, 10, 10) main_layout.setSpacing(15) # 左侧布局 - 图像显示 left_layout QVBoxLayout() left_layout.setSpacing(15) # 原始图像显示 self.original_group self.create_image_group(原始图像, 等待加载图像...) left_layout.addWidget(self.original_group) # 检测结果显示 self.result_group self.create_image_group(检测结果, 检测结果将显示在这里) left_layout.addWidget(self.result_group) main_layout.addLayout(left_layout, 3) # 右侧布局 - 控制面板 right_layout QVBoxLayout() right_layout.setSpacing(15) # 模型控制组 right_layout.addWidget(self.create_model_group()) # 参数控制组 right_layout.addWidget(self.create_parameter_group()) # 功能按钮组 right_layout.addWidget(self.create_function_group()) # 结果表格组 right_layout.addWidget(self.create_results_table()) main_layout.addLayout(right_layout, 1) # 状态栏 self.status_bar QStatusBar() self.setStatusBar(self.status_bar) # 进度条 self.progress_bar QProgressBar() self.progress_bar.setVisible(False) self.status_bar.addPermanentWidget(self.progress_bar) def create_image_group(self, title, placeholder_text): 创建图像显示组 group QGroupBox(title) group.setMinimumHeight(400) layout QVBoxLayout() label QLabel(placeholder_text) label.setAlignment(Qt.AlignCenter) label.setStyleSheet( QLabel { background-color: #F8F9FA; border: 2px dashed #DEE2E6; border-radius: 8px; color: #6C757D; font-size: 14px; padding: 20px; } ) label.setMinimumHeight(380) layout.addWidget(label) group.setLayout(layout) return group, label def create_model_group(self): 创建模型控制组 group QGroupBox(模型设置) layout QVBoxLayout() # 模型选择 self.model_combo QComboBox() self.model_combo.addItems([yolov8s.pt, yolov8m.pt, yolov8l.pt]) # 加载按钮 self.load_btn QPushButton(加载模型) self.load_btn.setStyleSheet(self.get_button_style(primary)) layout.addWidget(QLabel(选择模型:)) layout.addWidget(self.model_combo) layout.addWidget(self.load_btn) layout.addSpacing(10) # 模型信息显示 self.model_info_label QLabel(模型未加载) self.model_info_label.setStyleSheet(color: #6C757D; font-size: 12px;) layout.addWidget(self.model_info_label) group.setLayout(layout) return group def create_parameter_group(self): 创建参数控制组 group QGroupBox(检测参数) layout QVBoxLayout() # 置信度阈值 conf_layout QVBoxLayout() conf_layout.addWidget(QLabel(置信度阈值:)) self.conf_slider QSlider(Qt.Horizontal) self.conf_slider.setRange(1, 99) self.conf_slider.setValue(25) self.conf_label QLabel(0.25) self.conf_label.setAlignment(Qt.AlignCenter) self.conf_label.setStyleSheet(font-weight: bold; color: #007BFF;) conf_layout.addWidget(self.conf_slider) conf_layout.addWidget(self.conf_label) layout.addLayout(conf_layout) layout.addSpacing(15) # IoU阈值 iou_layout QVBoxLayout() iou_layout.addWidget(QLabel(IoU阈值:)) self.iou_slider QSlider(Qt.Horizontal) self.iou_slider.setRange(1, 99) self.iou_slider.setValue(45) self.iou_label QLabel(0.45) self.iou_label.setAlignment(Qt.AlignCenter) self.iou_label.setStyleSheet(font-weight: bold; color: #007BFF;) iou_layout.addWidget(self.iou_slider) iou_layout.addWidget(self.iou_label) layout.addLayout(iou_layout) group.setLayout(layout) return group def create_function_group(self): 创建功能按钮组 group QGroupBox(检测功能) layout QVBoxLayout() buttons [ (图片检测, image, primary), (视频检测, video, success), (摄像头检测, camera, info), (停止检测, stop, danger), (保存结果, save, warning) ] for text, name, style in buttons: btn QPushButton(text) btn.setProperty(function, name) btn.setStyleSheet(self.get_button_style(style)) if name stop: btn.setEnabled(False) layout.addWidget(btn) group.setLayout(layout) return group def create_results_table(self): 创建结果表格 group QGroupBox(检测结果详情) layout QVBoxLayout() self.results_table QTableWidget() self.results_table.setColumnCount(5) self.results_table.setHorizontalHeaderLabels([类别, 置信度, 数量, 位置, 尺寸]) self.results_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.results_table.setEditTriggers(QTableWidget.NoEditTriggers) layout.addWidget(self.results_table) group.setLayout(layout) return group def get_button_style(self, style_type): 获取按钮样式 styles { primary: QPushButton { background-color: #007BFF; color: white; border: none; padding: 10px; border-radius: 5px; font-weight: bold; } QPushButton:hover { background-color: #0056B3; } QPushButton:disabled { background-color: #6C757D; } , success: QPushButton { background-color: #28A745; color: white; border: none; padding: 10px; border-radius: 5px; font-weight: bold; } QPushButton:hover { background-color: #1E7E34; } , # ... 其他样式定义 } return styles.get(style_type, styles[primary]) def setup_connections(self): 设置信号连接 # 模型加载 self.load_btn.clicked.connect(self.load_model) # 参数更新 self.conf_slider.valueChanged.connect(self.update_conf_label) self.iou_slider.valueChanged.connect(self.update_iou_label) # 功能按钮 for btn in self.findChildren(QPushButton): if btn.property(function): func_name btn.property(function) if func_name image: btn.clicked.connect(self.detect_image) elif func_name video: btn.clicked.connect(self.detect_video) # ... 其他功能连接 def load_model(self): 加载模型 try: model_path self.model_combo.currentText() self.model YOLO(model_path) self.model_info_label.setText(f模型加载成功: {os.path.basename(model_path)}) self.status_bar.showMessage(模型加载成功, 3000) except Exception as e: QMessageBox.critical(self, 错误, f模型加载失败: {str(e)}) def update_conf_label(self): 更新置信度标签 conf self.conf_slider.value() / 100 self.conf_label.setText(f{conf:.2f}) def update_iou_label(self): 更新IoU标签 iou self.iou_slider.value() / 100 self.iou_label.setText(f{iou:.2f}) def detect_image(self): 图片检测功能 if not self.model: QMessageBox.warning(self, 警告, 请先加载模型) return file_path, _ QFileDialog.getOpenFileName( self, 选择图片, , 图片文件 (*.jpg *.jpeg *.png *.bmp);;所有文件 (*) ) if file_path: self.process_image(file_path) def process_image(self, image_path): 处理单张图片 try: # 读取并显示原始图像 image cv2.imread(image_path) image_rgb cv2.cvtColor(image, cv2.COLOR_BGR2RGB) self.display_image(image_rgb, self.original_label) # 在子线程中进行检测 self.progress_bar.setVisible(True) self.progress_bar.setRange(0, 0) # 无限进度条 self.detection_thread DetectionThread( self.model, image_rgb, self.conf_slider.value() / 100, self.iou_slider.value() / 100 ) self.detection_thread.finished.connect(self.on_detection_finished) self.detection_thread.error.connect(self.on_detection_error) self.detection_thread.start() except Exception as e: QMessageBox.critical(self, 错误, f图像处理失败: {str(e)}) def on_detection_finished(self, results): 检测完成回调 self.progress_bar.setVisible(False) # 显示检测结果 result_image results[0].plot() self.display_image(result_image, self.result_label) # 更新结果表格 self.update_results_table(results[0]) self.status_bar.showMessage(检测完成, 3000) def on_detection_error(self, error_msg): 检测错误回调 self.progress_bar.setVisible(False) QMessageBox.critical(self, 错误, f检测失败: {error_msg}) def display_image(self, image, label): 在QLabel中显示图像 h, w, ch image.shape bytes_per_line ch * w q_img QImage(image.data, w, h, bytes_per_line, QImage.Format_RGB888) pixmap QPixmap.fromImage(q_img) # 缩放适应标签大小 scaled_pixmap pixmap.scaled( label.width() - 20, label.height() - 20, Qt.KeepAspectRatio, Qt.SmoothTransformation ) label.setPixmap(scaled_pixmap) def update_results_table(self, results): 更新结果表格 self.results_table.setRowCount(0) if not results.boxes: return boxes results.boxes for i, (cls, conf, xyxy) in enumerate(zip(boxes.cls, boxes.conf, boxes.xyxy)): row self.results_table.rowCount() self.results_table.insertRow(row) # 类别名称 class_name results.names[int(cls)] self.results_table.setItem(row, 0, QTableWidgetItem(class_name)) # 置信度 self.results_table.setItem(row, 1, QTableWidgetItem(f{conf:.3f})) # 数量同类目标计数 same_class_count sum(1 for c in boxes.cls if int(c) int(cls)) self.results_table.setItem(row, 2, QTableWidgetItem(str(same_class_count))) # 位置 x1, y1, x2, y2 xyxy position f({x1:.0f}, {y1:.0f}) self.results_table.setItem(row, 3, QTableWidgetItem(position)) # 尺寸 width x2 - x1 height y2 - y1 size f{width:.0f}×{height:.0f} self.results_table.setItem(row, 4, QTableWidgetItem(size)) def main(): app QApplication(sys.argv) window UnderwaterDetectionUI() window.show() sys.exit(app.exec_()) if __name__ __main__: main()5.2 实时检测功能实现对于视频和摄像头实时检测需要处理帧率和性能优化class VideoDetectionHandler: 视频检测处理器 def __init__(self, model, conf_threshold0.25, iou_threshold0.45): self.model model self.conf_threshold conf_threshold self.iou_threshold iou_threshold self.is_running False self.current_frame None self.results None def process_frame(self, frame): 处理单帧 if not self.is_running: return frame try: # 调整帧尺寸以提高性能 small_frame cv2.resize(frame, (640, 640)) results self.model.predict( small_frame, confself.conf_threshold, iouself.iou_threshold, verboseFalse ) # 将检测结果绘制到原尺寸帧上 result_frame results[0].plot() result_frame cv2.resize(result_frame, (frame.shape[1], frame.shape[0])) self.results results[0] return result_frame except Exception as e: print(f帧处理错误: {e}) return frame def start(self): self.is_running True def stop(self): self.is_running False self.results None6. 系统部署与性能优化6.1 生产环境部署配置创建部署配置文件deploy_config.yaml# 部署配置 deployment: model_path: runs/detect/train/weights/best.pt input_sources: