YOLOv8热成像人员检测:从环境配置到系统部署完整指南

YOLOv8热成像人员检测:从环境配置到系统部署完整指南
在实际项目中部署基于深度学习的视觉检测系统时环境配置和模型适配往往是最大的技术瓶颈。特别是将YOLOv8与热成像技术结合用于人员检测的场景既要处理红外图像的特殊性又要保证检测精度和实时性。本文基于真实项目经验完整拆解从环境搭建、数据集处理、模型训练到系统集成的全流程提供可复用的代码和配置方案。无论你是刚接触计算机视觉的新手还是需要将热成像检测落地到安防、消防等实际场景的开发者都能通过本文获得可直接运行的完整解决方案。我们将重点解决热成像图像对比度低、特征不明显导致的检测难题并分享在实际部署中的性能优化经验。1. 项目背景与技术选型1.1 热成像人员检测的应用价值热成像技术通过检测物体发出的红外辐射生成图像不依赖可见光在黑暗、烟雾、雾霾等恶劣环境下具有独特优势。人员检测作为热成像技术的重要应用场景广泛用于安防监控夜间巡逻、边境防控、重要区域入侵检测消防救援火场人员搜救、浓烟环境下生命探测工业安全高温作业区域人员监控、危险区域闯入预警疫情防控公共场所人流密度监测、发热人员筛查与传统可见光检测相比热成像人员检测具有全天候工作能力但同时也面临挑战热成像图像缺乏纹理细节、人员轮廓模糊、不同环境温度下特征变化大。1.2 YOLOv8在热成像检测中的优势YOLOv8作为YOLO系列的最新版本在精度和速度之间取得了更好的平衡特别适合热成像人员检测任务高精度检测改进的骨干网络和检测头设计对低对比度热成像图像有更好的特征提取能力实时性能在相同精度下比前代版本速度提升15-30%满足实时监控需求易于部署支持ONNX、TensorRT等多种格式导出便于嵌入式设备部署灵活训练提供完整的训练接口可针对热成像数据优化模型1.3 系统架构概述本系统采用模块化设计主要包含以下组件热成像人员检测系统/ ├── 数据采集模块热成像相机接口 ├── 预处理模块图像增强、归一化 ├── YOLOv8检测引擎模型推理、后处理 ├── 结果可视化模块边界框绘制、温度显示 ├── 报警输出模块人员计数、越界检测 └── 用户界面实时显示、参数配置2. 环境配置与依赖安装2.1 系统环境要求为确保系统稳定运行推荐以下环境配置操作系统Ubuntu 20.04/22.04 LTS 或 Windows 10/11Python版本3.8-3.103.11可能存在兼容性问题深度学习框架PyTorch 1.12.0 或 2.0.0GPU支持NVIDIA GPU可选CUDA 11.72.2 核心依赖安装创建独立的Python环境并安装必要依赖# 创建conda环境推荐 conda create -n yolov8-thermal python3.9 conda activate yolov8-thermal # 安装PyTorch根据CUDA版本选择 # CUDA 11.7 pip install torch1.13.1cu117 torchvision0.14.1cu117 --extra-index-url https://download.pytorch.org/whl/cu117 # 或CPU版本 pip install torch1.13.1cpu torchvision0.14.1cpu --extra-index-url https://download.pytorch.org/whl/cpu # 安装Ultralytics YOLOv8 pip install ultralytics # 安装图像处理和相关库 pip install opencv-python pillow numpy pandas matplotlib pip install seaborn scipy tqdm # 界面开发库PyQt5或Gradio pip install pyqt5 # 桌面应用 # 或 pip install gradio # Web界面2.3 环境验证安装完成后验证环境是否正确配置# environment_test.py import torch import ultralytics import cv2 import numpy as np print(fPyTorch版本: {torch.__version__}) print(fCUDA可用: {torch.cuda.is_available()}) print(fCUDA版本: {torch.version.cuda}) print(fYOLOv8版本: {ultralytics.__version__}) print(fOpenCV版本: {cv2.__version__}) # 测试GPU加速 if torch.cuda.is_available(): device torch.device(cuda) print(f使用GPU: {torch.cuda.get_device_name(0)}) else: device torch.device(cpu) print(使用CPU进行推理)3. 热成像数据集准备与处理3.1 热成像数据特点分析热成像数据与可见光图像有显著差异需要特殊处理单通道图像通常为灰度图包含温度信息动态范围大不同场景温度差异显著-20°C到500°C对比度低人体与背景温差可能很小噪声干扰受环境温度、反射等因素影响3.2 数据采集与标注规范针对热成像人员检测制定以下标注规范# 标注格式示例YOLO格式 # class x_center y_center width height 0 0.512 0.345 0.123 0.456 # 人员类别为0 # 温度信息存储可选 # 在图像元数据中记录温度范围 温度标定信息 - 最小温度20.5°C - 最大温度38.2°C - 温度单位摄氏度 3.3 数据增强策略为提升模型泛化能力针对热成像特点设计数据增强# thermal_augmentation.py import cv2 import numpy as np import albumentations as A def create_thermal_augmentation_pipeline(): 创建热成像专用的数据增强流水线 return A.Compose([ # 几何变换 A.HorizontalFlip(p0.5), A.RandomRotate90(p0.5), A.ShiftScaleRotate(shift_limit0.05, scale_limit0.1, rotate_limit10, p0.5), # 热成像特有增强 A.RandomBrightnessContrast(brightness_limit0.2, contrast_limit0.2, p0.3), A.GaussNoise(var_limit(10.0, 50.0), p0.2), A.Blur(blur_limit3, p0.1), # 温度模拟增强 A.RandomGamma(gamma_limit(80, 120), p0.3), # 模拟温度变化 ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_labels])) # 应用增强示例 def augment_thermal_image(image, bboxes, class_labels): transform create_thermal_augmentation_pipeline() augmented transform(imageimage, bboxesbboxes, class_labelsclass_labels) return augmented[image], augmented[bboxes], augmented[class_labels]3.4 数据集目录结构规范化的数据集结构便于训练和管理thermal_person_dataset/ ├── images/ │ ├── train/ │ │ ├── thermal_001.jpg │ │ ├── thermal_002.jpg │ │ └── ... │ └── val/ │ ├── thermal_101.jpg │ ├── thermal_102.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── thermal_001.txt │ │ ├── thermal_002.txt │ │ └── ... │ └── val/ │ ├── thermal_101.txt │ ├── thermal_102.txt │ └── ... └── dataset.yaml # 数据集配置文件4. YOLOv8模型训练与优化4.1 模型选择与配置根据热成像检测需求选择合适的YOLOv8模型# thermal_detection.yaml # 数据集配置文件 path: /path/to/thermal_person_dataset train: images/train val: images/val # 类别定义 names: 0: person # 模型配置根据需求选择 # YOLOv8n: 轻量级适合嵌入式设备 # YOLOv8s: 平衡型推荐大多数场景 # YOLOv8m: 高精度适合服务器部署4.2 自定义训练配置针对热成像特点调整训练参数# custom_train.py from ultralytics import YOLO import yaml def train_thermal_detector(): # 加载预训练模型 model YOLO(yolov8s.pt) # 使用小模型平衡速度与精度 # 训练配置 training_config { data: thermal_detection.yaml, epochs: 100, imgsz: 640, batch: 16, device: 0, # 使用GPU 0设为None使用CPU workers: 4, optimizer: auto, lr0: 0.01, # 初始学习率 lrf: 0.01, # 最终学习率 momentum: 0.937, weight_decay: 0.0005, warmup_epochs: 3.0, warmup_momentum: 0.8, box: 7.5, # 调整边界框损失权重 cls: 0.5, # 调整分类损失权重 dfl: 1.5, # 调整分布焦点损失权重 fl_gamma: 0.0, # 焦点损失gamma hsv_h: 0.015, # 色相增强热成像中作用有限 hsv_s: 0.7, # 饱和度增强 hsv_v: 0.4, # 明度增强 degrees: 0.0, # 旋转角度热成像通常不需要大角度旋转 translate: 0.1, scale: 0.5, shear: 0.0, perspective: 0.0, flipud: 0.0, fliplr: 0.5, mosaic: 1.0, # 马赛克增强 mixup: 0.0, # 热成像不建议使用mixup copy_paste: 0.0 } # 开始训练 results model.train(**training_config) return results if __name__ __main__: train_thermal_detector()4.3 热成像专用优化技巧针对热成像检测的特殊性采用以下优化策略# thermal_optimization.py import torch import torch.nn as nn from ultralytics.nn.modules import Detect class ThermalAwareDetect(Detect): 热成像感知的检测头优化 def __init__(self, nc80, ch()): super().__init__(nc, ch) # 增加温度特征提取层 self.temperature_aware nn.Sequential( nn.Conv2d(ch[0], 64, 3, padding1), nn.BatchNorm2d(64), nn.SiLU(), nn.Conv2d(64, 32, 3, padding1), nn.BatchNorm2d(32), nn.SiLU(), ) def forward(self, x): # 原始检测逻辑 original_output super().forward(x) # 温度感知增强 temp_features self.temperature_aware(x[0]) # 将温度特征融合到检测结果中 return original_output def apply_thermal_optimizations(model): 应用热成像专用优化 # 替换检测头 model.model[-1] ThermalAwareDetect( ncmodel.model[-1].nc, chmodel.model[-1].ch ) return model5. 系统集成与界面开发5.1 核心检测引擎实现# thermal_detector.py import cv2 import numpy as np from ultralytics import YOLO from typing import List, Tuple, Dict import time class ThermalPersonDetector: 热成像人员检测器 def __init__(self, model_path: str, conf_threshold: float 0.5, iou_threshold: float 0.5): 初始化检测器 Args: model_path: 训练好的模型路径 conf_threshold: 置信度阈值 iou_threshold: IOU阈值 self.model YOLO(model_path) self.conf_threshold conf_threshold self.iou_threshold iou_threshold self.class_names [person] # 热成像检测通常只有人员类别 def preprocess_thermal_image(self, image: np.ndarray) - np.ndarray: 预处理热成像图像 Args: image: 输入热成像图像 Returns: 预处理后的图像 # 热成像图像增强 if len(image.shape) 2: # 单通道 image cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) # 对比度增强 image self.enhance_contrast(image) return image def enhance_contrast(self, image: np.ndarray) - np.ndarray: 增强热成像图像对比度 # CLAHE对比度受限自适应直方图均衡化 clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) if len(image.shape) 3: lab cv2.cvtColor(image, cv2.COLOR_BGR2LAB) lab[:,:,0] clahe.apply(lab[:,:,0]) image cv2.cvtColor(lab, cv2.COLOR_LAB2BGR) else: image clahe.apply(image) return image def detect(self, image: np.ndarray) - Dict: 执行人员检测 Args: image: 输入图像 Returns: 检测结果字典 # 预处理 processed_image self.preprocess_thermal_image(image) # YOLOv8推理 results self.model( processed_image, confself.conf_threshold, iouself.iou_threshold, verboseFalse ) # 解析结果 detections [] for result in results: boxes result.boxes if boxes is not None: for box in boxes: detection { bbox: box.xyxy[0].cpu().numpy(), # [x1, y1, x2, y2] confidence: box.conf[0].cpu().numpy(), class_id: int(box.cls[0].cpu().numpy()), class_name: self.class_names[int(box.cls[0].cpu().numpy())] } detections.append(detection) return { detections: detections, original_image: image, processed_image: processed_image, inference_time: results[0].speed[inference] if results else 0 } def draw_detections(self, image: np.ndarray, detections: List[Dict]) - np.ndarray: 在图像上绘制检测结果 Args: image: 原始图像 detections: 检测结果列表 Returns: 绘制了检测框的图像 result_image image.copy() for detection in detections: bbox detection[bbox] confidence detection[confidence] class_name detection[class_name] # 绘制边界框 x1, y1, x2, y2 map(int, bbox) cv2.rectangle(result_image, (x1, y1), (x2, y2), (0, 255, 0), 2) # 绘制标签 label f{class_name}: {confidence:.2f} label_size cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 2)[0] cv2.rectangle(result_image, (x1, y1 - label_size[1] - 10), (x1 label_size[0], y1), (0, 255, 0), -1) cv2.putText(result_image, label, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 2) return result_image5.2 PyQt5用户界面开发# thermal_ui.py import sys import cv2 import numpy as np from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QSlider, QSpinBox, QComboBox, QGroupBox, QFileDialog, QMessageBox, QWidget) from PyQt5.QtCore import QTimer, Qt, pyqtSignal, QThread from PyQt5.QtGui import QImage, QPixmap from thermal_detector import ThermalPersonDetector class VideoThread(QThread): 视频处理线程 frame_processed pyqtSignal(np.ndarray, list, float) def __init__(self, detector, video_source0): super().__init__() self.detector detector self.video_source video_source self.running True self.paused False def run(self): cap cv2.VideoCapture(self.video_source) while self.running: if not self.paused: ret, frame cap.read() if ret: # 执行检测 results self.detector.detect(frame) detections results[detections] inference_time results[inference_time] # 绘制结果 result_frame self.detector.draw_detections(frame, detections) # 发送信号 self.frame_processed.emit(result_frame, detections, inference_time) else: break self.msleep(30) # 控制帧率 cap.release() def stop(self): self.running False self.wait() class ThermalDetectionUI(QMainWindow): 热成像人员检测主界面 def __init__(self): super().__init__() self.detector None self.video_thread None self.init_ui() def init_ui(self): 初始化用户界面 self.setWindowTitle(YOLOv8热成像人员检测系统) self.setGeometry(100, 100, 1200, 800) # 中央部件 central_widget QWidget() self.setCentralWidget(central_widget) # 主布局 main_layout QHBoxLayout() central_widget.setLayout(main_layout) # 左侧视频显示区域 left_layout QVBoxLayout() # 视频显示标签 self.video_label QLabel() self.video_label.setMinimumSize(800, 600) self.video_label.setStyleSheet(border: 1px solid gray;) self.video_label.setAlignment(Qt.AlignCenter) self.video_label.setText(视频显示区域) left_layout.addWidget(self.video_label) # 控制按钮 control_layout QHBoxLayout() self.start_btn QPushButton(开始检测) self.stop_btn QPushButton(停止检测) self.load_model_btn QPushButton(加载模型) self.camera_combo QComboBox() self.camera_combo.addItems([摄像头0, 摄像头1, 视频文件]) control_layout.addWidget(self.load_model_btn) control_layout.addWidget(self.start_btn) control_layout.addWidget(self.stop_btn) control_layout.addWidget(QLabel(视频源:)) control_layout.addWidget(self.camera_combo) left_layout.addLayout(control_layout) # 右侧控制面板 right_layout QVBoxLayout() # 检测参数组 param_group QGroupBox(检测参数) param_layout QVBoxLayout() # 置信度阈值 conf_layout QHBoxLayout() conf_layout.addWidget(QLabel(置信度阈值:)) self.conf_slider QSlider(Qt.Horizontal) self.conf_slider.setRange(0, 100) self.conf_slider.setValue(50) self.conf_value QLabel(0.50) conf_layout.addWidget(self.conf_slider) conf_layout.addWidget(self.conf_value) param_layout.addLayout(conf_layout) # IOU阈值 iou_layout QHBoxLayout() iou_layout.addWidget(QLabel(IOU阈值:)) self.iou_slider QSlider(Qt.Horizontal) self.iou_slider.setRange(0, 100) self.iou_slider.setValue(50) self.iou_value QLabel(0.50) iou_layout.addWidget(self.iou_slider) iou_layout.addWidget(self.iou_value) param_layout.addLayout(iou_layout) param_group.setLayout(param_layout) right_layout.addWidget(param_group) # 统计信息组 stats_group QGroupBox(检测统计) stats_layout QVBoxLayout() self.detection_count QLabel(检测到人员: 0) self.fps_label QLabel(FPS: 0) self.inference_time_label QLabel(推理时间: 0ms) stats_layout.addWidget(self.detection_count) stats_layout.addWidget(self.fps_label) stats_layout.addWidget(self.inference_time_label) stats_group.setLayout(stats_layout) right_layout.addWidget(stats_group) # 添加到主布局 main_layout.addLayout(left_layout, 3) main_layout.addLayout(right_layout, 1) # 连接信号槽 self.setup_connections() def setup_connections(self): 设置信号槽连接 self.load_model_btn.clicked.connect(self.load_model) self.start_btn.clicked.connect(self.start_detection) self.stop_btn.clicked.connect(self.stop_detection) self.conf_slider.valueChanged.connect(self.update_conf_threshold) self.iou_slider.valueChanged.connect(self.update_iou_threshold) def load_model(self): 加载YOLOv8模型 model_path, _ QFileDialog.getOpenFileName( self, 选择YOLOv8模型文件, , 模型文件 (*.pt)) if model_path: try: self.detector ThermalPersonDetector(model_path) QMessageBox.information(self, 成功, 模型加载成功) except Exception as e: QMessageBox.critical(self, 错误, f模型加载失败: {str(e)}) def start_detection(self): 开始检测 if self.detector is None: QMessageBox.warning(self, 警告, 请先加载模型) return # 更新检测参数 conf_threshold self.conf_slider.value() / 100.0 iou_threshold self.iou_slider.value() / 100.0 self.detector.conf_threshold conf_threshold self.detector.iou_threshold iou_threshold # 启动视频线程 video_source 0 # 默认摄像头 if self.camera_combo.currentText() 视频文件: video_path, _ QFileDialog.getOpenFileName( self, 选择视频文件, , 视频文件 (*.mp4 *.avi *.mov)) if video_path: video_source video_path else: return self.video_thread VideoThread(self.detector, video_source) self.video_thread.frame_processed.connect(self.update_frame) self.video_thread.start() self.start_btn.setEnabled(False) self.stop_btn.setEnabled(True) def stop_detection(self): 停止检测 if self.video_thread: self.video_thread.stop() self.video_thread None self.start_btn.setEnabled(True) self.stop_btn.setEnabled(False) self.video_label.setText(视频显示区域) def update_frame(self, frame, detections, inference_time): 更新视频帧显示 # 转换图像格式 frame_rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch frame_rgb.shape bytes_per_line ch * w qt_image QImage(frame_rgb.data, w, h, bytes_per_line, QImage.Format_RGB888) # 显示图像 self.video_label.setPixmap(QPixmap.fromImage(qt_image)) # 更新统计信息 self.detection_count.setText(f检测到人员: {len(detections)}) self.inference_time_label.setText(f推理时间: {inference_time:.1f}ms) def update_conf_threshold(self, value): 更新置信度阈值 conf_threshold value / 100.0 self.conf_value.setText(f{conf_threshold:.2f}) if self.detector: self.detector.conf_threshold conf_threshold def update_iou_threshold(self, value): 更新IOU阈值 iou_threshold value / 100.0 self.iou_value.setText(f{iou_threshold:.2f}) if self.detector: self.detector.iou_threshold iou_threshold def main(): app QApplication(sys.argv) window ThermalDetectionUI() window.show() sys.exit(app.exec_()) if __name__ __main__: main()6. 性能优化与部署方案6.1 推理速度优化针对实时检测需求采用以下优化策略# optimization.py import torch import onnxruntime as ort from ultralytics import YOLO class OptimizedThermalDetector: 优化版热成像检测器 def __init__(self, model_path: str, use_onnx: bool True): self.use_onnx use_onnx if use_onnx: # ONNX Runtime推理更快 self.session ort.InferenceSession(model_path) else: # PyTorch推理 self.model YOLO(model_path) # 模型优化 self.optimize_model() def optimize_model(self): 优化PyTorch模型 if hasattr(self, model): # 半精度推理 self.model.model.half() # FP16 # 启用TensorRT如果可用 if torch.cuda.is_available(): self.model.model.cuda() # 模型编译PyTorch 2.0 if hasattr(torch, compile): self.model.model torch.compile(self.model.model) def export_to_onnx(self, output_path: str): 导出为ONNX格式 if hasattr(self, model): self.model.export(formatonnx, imgsz640, simplifyTrue) def detect_optimized(self, image: np.ndarray) - Dict: 优化版检测方法 if self.use_onnx: return self.detect_onnx(image) else: return self.detect_torch(image) def detect_onnx(self, image: np.ndarray) - Dict: ONNX推理 # 预处理图像 input_tensor self.preprocess_for_onnx(image) # ONNX推理 outputs self.session.run(None, {images: input_tensor}) # 后处理 return self.postprocess_onnx(outputs, image.shape) def preprocess_for_onnx(self, image: np.ndarray) - np.ndarray: ONNX输入预处理 # 调整尺寸到640x640 resized cv2.resize(image, (640, 640)) # 归一化 normalized resized.astype(np.float32) / 255.0 # 调整通道顺序 tensor normalized.transpose(2, 0, 1) # 添加批次维度 tensor np.expand_dims(tensor, axis0) return tensor6.2 嵌入式设备部署针对RK3568、Jetson等嵌入式设备的部署方案# embedded_deployment.py import os import subprocess from pathlib import Path class EmbeddedDeployer: 嵌入式设备部署工具 def __init__(self, model_path: str, target_device: str rk3568): self.model_path model_path self.target_device target_device def convert_to_rknn(self, output_path: str): 转换为RKNN格式瑞芯微芯片 # 需要RKNN Toolkit try: from rknn.api import RKNN # 创建RKNN对象 rknn RKNN() # 模型配置 rknn.config( target_platform[rk3568], quantizeTrue, # 量化加速 output_optimize1 ) # 加载ONNX模型 rknn.load_onnx(modelself.model_path) # 构建模型 rknn.build(do_quantizationTrue, dataset./quantization.txt) # 导出RKNN模型 rknn.export_rknn(output_path) print(fRKNN模型已导出: {output_path}) except ImportError: print(请安装RKNN Toolkit) def create_deployment_script(self, output_dir: str): 创建部署脚本 script_content f#!/bin/bash # 热成像人员检测部署脚本 # 目标设备: {self.target_device} echo 开始部署热成像人员检测系统... # 创建目录 mkdir -p {output_dir}/models mkdir -p {output_dir}/scripts mkdir -p {output_dir}/config # 复制模型文件 cp {self.model_path} {output_dir}/models/ # 创建启动脚本 cat {output_dir}/scripts/start_detection.sh EOF #!/bin/bash cd $(dirname $0) python3 thermal_detection_app.py --model ../models/model.rknn --source 0 EOF chmod x {output_dir}/scripts/start_detection.sh echo 部署完成 echo 运行命令: cd {output_dir} ./scripts/start_detection.sh script_path Path(output_dir) / deploy.sh with open(script_path, w) as f: f.write(script_content) # 设置执行权限 os.chmod(script_path, 0o755) return script_path7. 实际应用与性能测试7.1 测试环境搭建建立标准化的测试流程# performance_test.py import time import cv2 import numpy as np from thermal_detector import ThermalPersonDetector class PerformanceTester: 性能测试工具 def __init__(self, model_path: str, test_video_path: str): self.detector ThermalPersonDetector(model_path) self.test_video_path test_video_path def run_comprehensive_test(self, duration: int 300) - Dict: 运行综合性能测试 results { frame_count: 0, total_detections: 0, total_inference_time: 0, fps_stats: [], detection_accuracy: [], memory_usage: [] } cap cv2.VideoCapture(self.test_video_path) start_time time.time() while time.time() - start_time duration: ret, frame cap.read() if not ret: break # 执行检测 inference_start time.time() detection_results self.detector.detect(frame) inference_time time.time() - inference_start # 记录结果 results[frame_count] 1 results[total_detections] len(detection_results[detections]) results[total_inference_time] inference_time results[fps_stats].append(1.0 / inference_time if inference_time 0 else 0) # 计算当前FPS current_fps 1.0 / inference_time if inference_time 0 else 0 print(f帧: {results[frame_count]}, FPS: {current_fps:.1f}, 检测数: {len(detection_results[detections])}) cap.release() # 计算统计信息 results[average_fps] np.mean(results[fps_stats]) results[average_inference_time] results[total_inference_time] / results[frame_count] results[detection_rate] results[total_detections] / results[frame_count] return results def generate_test_report(self, results: Dict) - str: 生成测试报告 report f 热成像人员检测系统性能测试报告 测试概要: - 总测试时长: {len(results[fps_stats])} 帧 - 平均FPS: {results[average_fps]:.2f} - 平均推理时间: {results[average_inference_time]*1000:.2f} ms - 平均每帧检测数: {results[detection_rate]:.2f} 性能分析: - 最高FPS: {np.max(results[fps_stats]):.2f} - 最低FPS: {np.min(results[fps_stats]):.2f} - FPS稳定性: {np.std(results[fps_stats]):.2f} 系统建议: if results[average_fps] 25: report -