onnx推理之ort.OrtValue.ortvalue_from_numpy 和 io_binding.bind_ortvalue_output 的组合功能

这是一个在 ONNX Runtime 中用于高性能GPU推理 的关键技术组合。


1. ort.OrtValue.ortvalue_from_numpy 的作用

这个函数的作用是从一个 NumPy 数组创建一个 ONNX Runtime 的 OrtValue 对象,并且明确指定该对象所在的内存位置(如 GPU)。

参数解释:

  • numpy: 源 NumPy 数组。

  • "cuda": 指定新创建的 OrtValue 所使用的内存分配器。这里 "cuda" 表示使用 CUDA 分配器,即在 GPU 上分配内存。

  • device_id=0: 指定使用哪一块 GPU(设备 ID 为 0)。

它的核心功能是:

  1. 数据迁移:它会将 NumPy 数组中的数据(原本在CPU内存中)拷贝到指定的GPU设备上。

  2. 创建关联:在GPU上创建一块新的内存,并创建一个 OrtValue 对象来管理这块GPU内存,同时将其与原始NumPy数组的数据类型和形状信息关联起来。

简单来说:ortvalue_from_numpy(numpy, "cuda", 0) 

import os import sys import time import json import ctypes import threading import numpy as np import cv2 import onnxruntime as ort from mss import mss from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QSlider, QComboBox, QCheckBox, QFileDialog, QGroupBox, QSpinBox, QDoubleSpinBox, QTabWidget, QMessageBox, QProgressBar) from PyQt5.QtCore import Qt, QTimer, QSettings, QPoint, QThread, pyqtSignal from PyQt5.QtGui import QImage, QPixmap, QPainter, QPen, QColor, QFont from pynput import keyboard, mouse # ============================================== # 常量定义 # ============================================== DEFAULT_CONF_THRESHOLD = 70 # 默认置信度阈值(百分比) DEFAULT_CIRCLE_RADIUS = 300 # 默认圆形范围(像素) DEFAULT_MOVE_SPEED = 10 # 默认移动速度(百分比) DEFAULT_SHOW_CONTOURS = True DEFAULT_SHOW_CONF = True # ============================================== # 模型类 (AIModel) # ============================================== class AIModel: def __init__(self, model_path=None): self.model = None self.input_name = None self.output_name = None self.model_loaded = False if model_path: self.load_model(model_path) def load_model(self, model_path): try: # 尝试使用GPU加速,如果不可用则使用CPU providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] self.model = ort.InferenceSession(model_path, providers=providers) self.input_name = self.model.get_inputs()[0].name self.output_name = self.model.get_outputs()[0].name self.model_loaded = True return True except Exception as e: print(f"[错误] 模型加载失败: {e}") self.model_loaded = False return False def predict(self, image, conf_threshold=0.5): if not self.model_loaded: return [], 0 try: # 记录推理开始时间 start_time = time.perf_counter() # 预处理图像 input_tensor = self.preprocess(image) # 执行推理 outputs = self.model.run([self.output_name], {self.input_name: input_tensor})[0] # 后处理结果 detections = self.postprocess(outputs, conf_threshold) # 计算推理时间(毫秒) inference_time = (time.perf_counter() - start_time) * 1000 return detections, inference_time except Exception as e: print(f"[错误] 模型推理失败: {e}") return [], 0 def preprocess(self, image): # 调整图像大小为模型输入尺寸 image = cv2.resize(image, (640, 640)) # 转换通道顺序 (HWC to CHW) image = image.transpose(2, 0, 1) # 添加批次维度并归一化 image = np.expand_dims(image, axis=0).astype(np.float32) / 255.0 return image def postprocess(self, outputs, conf_threshold): # 假设输出格式为 [batch, num_detections, 6] (x1, y1, x2, y2, conf, class_id) detections = [] for detection in outputs[0]: confidence = detection[4] if confidence > conf_threshold: x1, y1, x2, y2 = detection[:4] # 确保坐标值有效 if x1 < x2 and y1 < y2: detections.append({ 'box': [x1, y1, x2, y2], 'conf': confidence * 100, # 转换为百分比 'class_id': int(detection[5]), 'center': [(x1 + x2) / 2, (y1 + y2) / 2] }) return detections # ============================================== # 屏幕捕获类 (ScreenCapture) # ============================================== class ScreenCapture: def __init__(self): # 使用线程本地存储解决多线程问题 self.thread_local = threading.local() self.monitor = self.get_primary_monitor() self.last_capture_time = 0 self.capture_interval = 0.05 # 20 FPS def get_primary_monitor(self): """安全获取主显示器信息""" try: with mss() as temp_sct: for monitor in temp_sct.monitors: if monitor["left"] == 0 and monitor["top"] == 0: return monitor return temp_sct.monitors[0] except Exception as e: print(f"[错误] 获取显示器信息失败: {e}") # 返回默认值 return {"top": 0, "left": 0, "width": 1920, "height": 1080} def get_sct_instance(self): """获取当前线程的mss实例""" if not hasattr(self.thread_local, 'sct') or self.thread_local.sct is None: try: self.thread_local.sct = mss() except Exception as e: print(f"[错误] 创建mss实例失败: {e}") return None return self.thread_local.sct def capture(self): current_time = time.time() # 控制捕获频率 if current_time - self.last_capture_time < self.capture_interval: return None try: sct = self.get_sct_instance() if sct is None: return None # 捕获屏幕 img = np.array(sct.grab(self.monitor)) # 转换颜色空间 (BGRA to BGR) self.last_capture_time = current_time return cv2.cvtColor(img, cv2.COLOR_BGRA2BGR) except Exception as e: print(f"[错误] 屏幕捕获失败: {e}") # 重置当前线程的sct实例 if hasattr(self.thread_local, 'sct'): self.thread_local.sct = None return None # ============================================== # 瞄准系统主类 (AimbotSystem) # ============================================== class AimbotSystem(QThread): # 信号用于更新UI status_update = pyqtSignal(float, float, int, bool) def __init__(self): super().__init__() self.capture = ScreenCapture() self.model = AIModel() self.active = False self.conf_threshold = DEFAULT_CONF_THRESHOLD self.circle_radius = DEFAULT_CIRCLE_RADIUS self.move_speed = DEFAULT_MOVE_SPEED self.show_contours = DEFAULT_SHOW_CONTOURS self.show_conf = DEFAULT_SHOW_CONF self.targets = [] self.fps = 0 self.inference_time = 0 self.last_time = time.time() self.key_bind = None self.key_listener = None self.mouse_listener = None self.bound_key = None self.bound_button = None self.key_state = False self.running = True self.lock = threading.Lock() # 初始化按键监听器 self.start_listeners() def start_listeners(self): # 停止现有的监听器 self.stop_listeners() # 启动新的监听器 if self.bound_key: self.key_listener = keyboard.Listener( on_press=self.on_key_press, on_release=self.on_key_release ) self.key_listener.start() elif self.bound_button: self.mouse_listener = mouse.Listener( on_click=self.on_mouse_click ) self.mouse_listener.start() def stop_listeners(self): if self.key_listener: self.key_listener.stop() self.key_listener = None if self.mouse_listener: self.mouse_listener.stop() self.mouse_listener = None def on_key_press(self, key): try: if key == self.bound_key: self.active = True self.key_state = True except AttributeError: pass def on_key_release(self, key): try: if key == self.bound_key: self.active = False self.key_state = False except AttributeError: pass def on_mouse_click(self, x, y, button, pressed): if button == self.bound_button: self.active = pressed self.key_state = pressed def update_settings(self, conf_threshold, circle_radius, move_speed, show_contours, show_conf, key_bind=None, mouse_bind=None): with self.lock: self.conf_threshold = conf_threshold self.circle_radius = circle_radius self.move_speed = move_speed self.show_contours = show_contours self.show_conf = show_conf # 更新按键绑定 if key_bind: self.key_bind = key_bind self.bound_key = key_bind self.bound_button = None elif mouse_bind: self.key_bind = mouse_bind self.bound_button = mouse_bind self.bound_key = None # 重新启动监听器 self.start_listeners() def process_frame(self): try: start_time = time.time() # 捕获屏幕 frame = self.capture.capture() if frame is None: time.sleep(0.01) return # 确保捕获到有效帧 if frame.size == 0: print("[警告] 捕获到空帧") return screen_center = (frame.shape[1] // 2, frame.shape[0] // 2) # 执行推理 targets, inference_time = self.model.predict(frame, self.conf_threshold / 100.0) # 筛选圆形区域内的目标 valid_targets = [] for target in targets: center = target['center'] distance = np.sqrt((center[0] - screen_center[0])**2 + (center[1] - screen_center[1])**2) if distance <= self.circle_radius: valid_targets.append(target) # 找到最近的目标 closest_target = None min_distance = float('inf') for target in valid_targets: center = target['center'] distance = np.sqrt((center[0] - screen_center[0])**2 + (center[1] - screen_center[1])**2) if distance < min_distance: min_distance = distance closest_target = target # 移动鼠标 if self.active and closest_target: target_x, target_y = closest_target['center'] rel_x = screen_center[0] - target_x rel_y = screen_center[1] - target_y # 应用速度控制 move_x = rel_x * (self.move_speed / 100) move_y = rel_y * (self.move_speed / 100) move_mouse(move_x, move_y) # 计算FPS end_time = time.time() fps = 1 / (end_time - start_time) if end_time > start_time else 0 # 更新状态 self.status_update.emit(fps, inference_time, len(targets), self.key_state) self.targets = targets # 更新目标列表用于覆盖层绘制 def run(self): while self.running: try: self.process_frame() time.sleep(0.001) # 避免过度占用CPU except Exception as e: print(f"[错误] 处理帧时出错: {e}") def stop(self): self.running = False self.stop_listeners() # ============================================== # 覆盖窗口绘制类 (OverlayWindow) # ============================================== class OverlayWindow(QWidget): def __init__(self, aimbot): super().__init__() self.aimbot = aimbot self.setWindowTitle("Aimbot Overlay") self.setAttribute(Qt.WA_TranslucentBackground) self.setAttribute(Qt.WA_TransparentForMouseEvents) self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool) # 获取屏幕尺寸 screen = QApplication.primaryScreen().geometry() self.setGeometry(0, 0, screen.width(), screen.height()) self.targets = [] self.timer = QTimer() self.timer.timeout.connect(self.update_overlay) self.timer.start(50) # 20 FPS def update_overlay(self): # 安全获取目标列表 self.targets = self.aimbot.targets.copy() self.update() def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) # 绘制圆形区域 center = self.rect().center() painter.setPen(QPen(QColor(0, 255, 0, 150), 2)) painter.drawEllipse(center, self.aimbot.circle_radius, self.aimbot.circle_radius) # 绘制目标信息 for target in self.targets: x1, y1, x2, y2 = target['box'] center_x, center_y = target['center'] # 绘制目标框 if self.aimbot.show_contours: painter.setPen(QPen(QColor(255, 0, 0, 200), 2)) painter.drawRect(int(x1), int(y1), int(x2 - x1), int(y2 - y1)) # 绘制中心点 painter.setPen(QPen(QColor(0, 0, 255, 200), 4)) painter.drawPoint(int(center_x), int(center_y)) # 绘制置信度 (百分比形式) if self.aimbot.show_conf: painter.setPen(QColor(255, 255, 255)) painter.setFont(QFont('Arial', 10)) painter.drawText( int(x1), int(y1) - 5, f"{target['conf']:.1f}%" ) # ============================================== # 控制面板类 (ControlPanel) # ============================================== class ControlPanel(QMainWindow): def __init__(self, aimbot): super().__init__() self.aimbot = aimbot self.setWindowTitle("AI瞄准控制系统") self.setGeometry(100, 100, 500, 600) # 初始化设置对象 self.settings = QSettings("AimbotConfig.ini", QSettings.IniFormat) # 主布局 main_widget = QWidget() self.setCentralWidget(main_widget) main_layout = QVBoxLayout(main_widget) # 创建分页式菜单 self.tabs = QTabWidget() # 模型设置分页 model_tab = self.create_model_tab() # 瞄准设置分页 aim_tab = self.create_aim_tab() # 显示设置分页 display_tab = self.create_display_tab() # 状态信息分页 status_tab = self.create_status_tab() # 添加分页 self.tabs.addTab(model_tab, "模型设置") self.tabs.addTab(aim_tab, "瞄准设置") self.tabs.addTab(display_tab, "显示设置") self.tabs.addTab(status_tab, "状态信息") main_layout.addWidget(self.tabs) # 控制按钮 btn_layout = QHBoxLayout() self.apply_btn = QPushButton("应用设置") self.apply_btn.clicked.connect(self.apply_settings) btn_layout.addWidget(self.apply_btn) self.exit_btn = QPushButton("退出程序") self.exit_btn.clicked.connect(self.close_app) btn_layout.addWidget(self.exit_btn) main_layout.addLayout(btn_layout) # 连接信号 self.aimbot.status_update.connect(self.update_status) # 加载设置 self.load_settings() # 置顶窗口 self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint) # 按键绑定状态 self.binding = False self.binding_type = None self.bound_key = None self.bound_button = None def create_model_tab(self): tab = QWidget() layout = QVBoxLayout(tab) group = QGroupBox("模型设置") group_layout = QVBoxLayout() self.model_path_label = QLabel("未选择模型") group_layout.addWidget(self.model_path_label) btn_layout = QHBoxLayout() self.select_btn = QPushButton("选择模型") self.select_btn.clicked.connect(self.select_model) btn_layout.addWidget(self.select_btn) self.load_btn = QPushButton("加载模型") self.load_btn.clicked.connect(self.load_model) btn_layout.addWidget(self.load_btn) group_layout.addLayout(btn_layout) # 添加模型加载进度条 self.progress_bar = QProgressBar() self.progress_bar.setRange(0, 100) self.progress_bar.setVisible(False) group_layout.addWidget(self.progress_bar) group.setLayout(group_layout) layout.addWidget(group) layout.addStretch() return tab def create_aim_tab(self): tab = QWidget() layout = QVBoxLayout(tab) group = QGroupBox("瞄准设置") group_layout = QVBoxLayout() # 置信度阈值滑块 (百分比) conf_layout = QHBoxLayout() conf_layout.addWidget(QLabel("置信度阈值(%):")) self.conf_value_label = QLabel(f"{DEFAULT_CONF_THRESHOLD}%") conf_layout.addWidget(self.conf_value_label) group_layout.addLayout(conf_layout) self.conf_slider = QSlider(Qt.Horizontal) self.conf_slider.setRange(0, 100) self.conf_slider.setValue(DEFAULT_CONF_THRESHOLD) self.conf_slider.valueChanged.connect( lambda v: self.conf_value_label.setText(f"{v}%") ) group_layout.addWidget(self.conf_slider) # 圆形范围滑块 circle_layout = QHBoxLayout() circle_layout.addWidget(QLabel("圆形范围:")) self.circle_value_label = QLabel(f"{DEFAULT_CIRCLE_RADIUS}px") circle_layout.addWidget(self.circle_value_label) group_layout.addLayout(circle_layout) # 修复拼写错误 self.circle_slider = QSlider(Qt.Horizontal) self.circle_slider.setRange(50, 800) self.circle_slider.setValue(DEFAULT_CIRCLE_RADIUS) self.circle_slider.valueChanged.connect( lambda v: self.circle_value_label.setText(f"{v}px") ) group_layout.addWidget(self.circle_slider) # 移动速度滑块 speed_layout = QHBoxLayout() speed_layout.addWidget(QLabel("移动速度:")) self.speed_value_label = QLabel(f"{DEFAULT_MOVE_SPEED}%") speed_layout.addWidget(self.speed_value_label) group_layout.addLayout(speed_layout) self.speed_slider = QSlider(Qt.Horizontal) self.speed_slider.setRange(1, 100) self.speed_slider.setValue(DEFAULT_MOVE_SPEED) self.speed_slider.valueChanged.connect( lambda v: self.speed_value_label.setText(f"{v}%") ) group_layout.addWidget(self.speed_slider) # 按键绑定 key_layout = QHBoxLayout() key_layout.addWidget(QLabel("瞄准按键:")) self.key_bind_btn = QPushButton("绑定键盘按键") self.key_bind_btn.clicked.connect(lambda: self.bind_key("keyboard")) key_layout.addWidget(self.key_bind_btn) self.mouse_bind_btn = QPushButton("绑定鼠标按键") self.mouse_bind_btn.clicked.connect(lambda: self.bind_key("mouse")) key_layout.addWidget(self.mouse_bind_btn) group_layout.addLayout(key_layout) # 当前绑定显示 bind_display_layout = QHBoxLayout() bind_display_layout.addWidget(QLabel("当前绑定:")) self.bind_label = QLabel("未绑定") bind_display_layout.addWidget(self.bind_label) group_layout.addLayout(bind_display_layout) group.setLayout(group_layout) layout.addWidget(group) layout.addStretch() return tab def create_display_tab(self): tab = QWidget() layout = QVBoxLayout(tab) group = QGroupBox("显示设置") group_layout = QVBoxLayout() self.contour_check = QCheckBox("显示目标轮廓") self.contour_check.setChecked(DEFAULT_SHOW_CONTOURS) group_layout.addWidget(self.contour_check) self.conf_check = QCheckBox("显示置信度") self.conf_check.setChecked(DEFAULT_SHOW_CONF) group_layout.addWidget(self.conf_check) group.setLayout(group_layout) layout.addWidget(group) layout.addStretch() return tab def create_status_tab(self): tab = QWidget() layout = QVBoxLayout(tab) group = QGroupBox("状态信息") group_layout = QVBoxLayout() self.fps_label = QLabel("FPS: 0") group_layout.addWidget(self.fps_label) self.inference_label = QLabel("检测速度: 0 ms") group_layout.addWidget(self.inference_label) self.targets_label = QLabel("检测目标: 0") group_layout.addWidget(self.targets_label) self.bind_state_label = QLabel("绑定状态: 未激活") group_layout.addWidget(self.bind_state_label) # 添加系统信息 sys_info_layout = QHBoxLayout() sys_info_layout.addWidget(QLabel("CPU使用率:")) self.cpu_label = QLabel("0%") sys_info_layout.addWidget(self.cpu_label) group_layout.addLayout(sys_info_layout) group.setLayout(group_layout) layout.addWidget(group) layout.addStretch() return tab def select_model(self): file_path, _ = QFileDialog.getOpenFileName( self, "选择ONNX模型", "", "ONNX文件 (*.onnx)" ) if file_path: self.model_path = file_path self.model_path_label.setText(os.path.basename(file_path)) def load_model(self): if hasattr(self, 'model_path'): # 显示进度条 self.progress_bar.setVisible(True) self.progress_bar.setValue(0) # 在后台线程中加载模型 def load_in_background(): try: # 模拟加载过程 for i in range(1, 101): time.sleep(0.02) self.progress_bar.setValue(i) success = self.aimbot.model.load_model(self.model_path) if success: self.model_path_label.setText(f"已加载: {os.path.basename(self.model_path)}") else: QMessageBox.warning(self, "加载失败", "模型加载失败,请检查文件格式") except Exception as e: print(f"模型加载错误: {e}") QMessageBox.critical(self, "错误", f"加载模型时出错: {e}") finally: self.progress_bar.setVisible(False) # 启动后台线程 threading.Thread(target=load_in_background, daemon=True).start() def bind_key(self, bind_type): self.binding = True self.binding_type = bind_type # 提示用户 QMessageBox.information( self, "按键绑定", "请按下要绑定的按键 (按ESC取消绑定)\n\n" "按键将在按下时激活瞄准,松开时停止瞄准", QMessageBox.Ok ) # 启动全局监听器 if bind_type == "keyboard": self.key_listener = keyboard.Listener( on_press=self.on_bind_key_press, on_release=self.on_bind_key_release ) self.key_listener.start() else: self.mouse_listener = mouse.Listener( on_click=self.on_bind_mouse_click ) self.mouse_listener.start() def on_bind_key_press(self, key): if key == keyboard.Key.esc: self.cancel_binding() return # 记录按下的按键 self.bound_key = key self.bind_label.setText(f"键盘按键: {key}") self.cancel_binding() def on_bind_key_release(self, key): pass def on_bind_mouse_click(self, x, y, button, pressed): if pressed: # 记录按下的鼠标按键 self.bound_button = button self.bind_label.setText(f"鼠标按键: {button.name}") self.cancel_binding() def cancel_binding(self): self.binding = False # 停止监听器 if hasattr(self, 'key_listener') and self.key_listener: self.key_listener.stop() if hasattr(self, 'mouse_listener') and self.mouse_listener: self.mouse_listener.stop() def apply_settings(self): conf_threshold = self.conf_slider.value() circle_radius = self.circle_slider.value() move_speed = self.speed_slider.value() show_contours = self.contour_check.isChecked() show_conf = self.conf_check.isChecked() self.aimbot.update_settings( conf_threshold, circle_radius, move_speed, show_contours, show_conf, self.bound_key, self.bound_button ) # 保存设置 self.save_settings() QMessageBox.information(self, "设置已应用", "所有设置已成功应用!") def update_status(self, fps, inference_time, targets_count, key_state): self.fps_label.setText(f"FPS: {fps:.1f}") self.inference_label.setText(f"检测速度: {inference_time:.1f} ms") self.targets_label.setText(f"检测目标: {targets_count}") if key_state: self.bind_state_label.setText("绑定状态: 激活中") else: self.bind_state_label.setText("绑定状态: 未激活") def save_settings(self): try: self.settings.setValue("conf_threshold", self.aimbot.conf_threshold) self.settings.setValue("circle_radius", self.aimbot.circle_radius) self.settings.setValue("move_speed", self.aimbot.move_speed) self.settings.setValue("show_contours", self.aimbot.show_contours) self.settings.setValue("show_conf", self.aimbot.show_conf) # 保存绑定按键 if self.bound_key: self.settings.setValue("bound_key", str(self.bound_key)) if self.bound_button: self.settings.setValue("bound_button", self.bound_button.name) self.settings.setValue("geometry", self.saveGeometry()) except Exception as e: print(f"保存设置时出错: {e}") QMessageBox.warning(self, "保存错误", f"保存设置时出错: {e}") def load_settings(self): try: # 加载基本设置 self.aimbot.conf_threshold = self.settings.value("conf_threshold", DEFAULT_CONF_THRESHOLD, int) self.aimbot.circle_radius = self.settings.value("circle_radius", DEFAULT_CIRCLE_RADIUS, int) self.aimbot.move_speed = self.settings.value("move_speed", DEFAULT_MOVE_SPEED, int) self.aimbot.show_contours = self.settings.value("show_contours", DEFAULT_SHOW_CONTOURS, bool) self.aimbot.show_conf = self.settings.value("show_conf", DEFAULT_SHOW_CONF, bool) # 恢复滑块位置 self.conf_slider.setValue(self.aimbot.conf_threshold) self.circle_slider.setValue(self.aimbot.circle_radius) self.speed_slider.setValue(self.aimbot.move_speed) # 更新标签显示 self.conf_value_label.setText(f"{self.aimbot.conf_threshold}%") self.circle_value_label.setText(f"{self.aimbot.circle_radius}px") self.speed_value_label.setText(f"{self.aimbot.move_speed}%") # 恢复复选框状态 self.contour_check.setChecked(self.aimbot.show_contours) self.conf_check.setChecked(self.aimbot.show_conf) # 加载绑定按键 bound_key_str = self.settings.value("bound_key", "") if bound_key_str: try: # 解析按键字符串 (例如 "Key.ctrl" 或 "Key.f1") key_name = bound_key_str.split('.')[1] self.bound_key = getattr(keyboard.Key, key_name) self.bind_label.setText(f"键盘按键: {key_name}") except Exception as e: print(f"加载键盘绑定失败: {e}") self.bound_key = None bound_button = self.settings.value("bound_button", "") if bound_button: try: # 解析鼠标按键 (例如 "left" 或 "right") self.bound_button = getattr(mouse.Button, bound_button) self.bind_label.setText(f"鼠标按键: {bound_button}") except Exception as e: print(f"加载鼠标绑定失败: {e}") self.bound_button = None # 更新瞄准系统的绑定 self.aimbot.update_settings( self.aimbot.conf_threshold, self.aimbot.circle_radius, self.aimbot.move_speed, self.aimbot.show_contours, self.aimbot.show_conf, key_bind=self.bound_key, mouse_bind=self.bound_button ) # 恢复窗口位置 if self.settings.contains("geometry"): self.restoreGeometry(self.settings.value("geometry")) except Exception as e: print(f"加载设置时出错: {e}") # 设置默认值 self.conf_slider.setValue(DEFAULT_CONF_THRESHOLD) self.circle_slider.setValue(DEFAULT_CIRCLE_RADIUS) self.speed_slider.setValue(DEFAULT_MOVE_SPEED) self.contour_check.setChecked(DEFAULT_SHOW_CONTOURS) self.conf_check.setChecked(DEFAULT_SHOW_CONF) self.bind_label.setText("未绑定") def close_app(self): self.save_settings() self.aimbot.stop() QApplication.quit() # ============================================== # 鼠标移动函数 (外部DLL) # ============================================== def move_mouse(x, y): try: if dll and usb_open >= 0: dll.move(int(x), int(y)) except Exception as e: print(f"移动鼠标失败: {e}") # ============================================== # 主程序 # ============================================== def main(): # 加载鼠标控制DLL try: global dll, usb_open dll = ctypes.cdll.LoadLibrary('./hiddll_x64.dll') usb_open = dll.open_hiddev_default() if usb_open < 0: print("USB硬件未连接,鼠标控制将不可用") else: print("USB硬件已连接") except Exception as e: print(f"加载鼠标DLL失败: {e}") dll = None usb_open = -1 app = QApplication(sys.argv) # 创建瞄准系统 aimbot = AimbotSystem() # 创建控制面板 control_panel = ControlPanel(aimbot) control_panel.show() # 创建覆盖窗口 overlay = OverlayWindow(aimbot) overlay.show() # 启动瞄准系统线程 aimbot.start() try: sys.exit(app.exec_()) except KeyboardInterrupt: aimbot.stop() if dll and usb_open >= 0: dll.close_hiddev() if __name__ == "__main__": main() 幫我合進裡面給我全部代碼
07-29
检查一下为什么量化过后还变慢了: import os import time import cv2 import numpy as np import onnxruntime as ort from ultralytics import YOLO from tqdm import tqdm 检查可用执行提供者 print(“可用ONNX执行提供者:”, ort.get_available_providers()) 配置ONNX Runtime ort_session_options = ort.SessionOptions() ort_session_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL ort_session_options.intra_op_num_threads = 8 # 优化线程数 加载训练好的模型 model = YOLO(“F:\code\python\mymodel\yolov8s_my.pt”) 加载量化模型 quant_model_path = ‘F:\code\python\mymodel\yolov8s_my_quantized_static.onnx’ quant_session = ort.InferenceSession( quant_model_path, sess_options=ort_session_options, providers=[‘CUDAExecutionProvider’, ‘CPUExecutionProvider’] # 优先使用GPU ) 设置测试集路径 test_dir = “F:\code\python\mydata\test” 创建结果保存目录 os.makedirs(“./res/normal”, exist_ok=True) os.makedirs(“./res/quant”, exist_ok=True) 获取所有jpg文件 all_files = [f for f in os.listdir(test_dir) if f.endswith(‘.jpg’)] 初始化速度统计变量 normal_total_time = 0 quant_total_time = 0 模型预热 print(“正在进行模型预热…”) warmup_img = np.zeros((640, 640, 3), dtype=np.uint8) model.predict(warmup_img, verbose=False) quant_session.run(None, {‘images’: np.zeros((1, 3, 640, 640), dtype=np.float32)}) print(“预热完成!”) 循环处理每张图像并计算速度 for i, file_name in enumerate(tqdm(all_files, desc=“处理进度”)): img_path = os.path.join(test_dir, file_name) img = cv2.imread(img_path) img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 转换为RGB # ===== 原始模型推理 ===== start_time = time.perf_counter() # 使用高精度计时器 normal_results = model.predict( source=img, save=False, verbose=False, imgsz=640, conf=0.25 ) normal_time = time.perf_counter() - start_time normal_total_time += normal_time # ===== 量化模型推理 ===== # 预处理 resized = cv2.resize(img_rgb, (640, 640)) input_tensor = resized.transpose(2, 0, 1).astype(np.float32) # HWC to CHW input_tensor = np.expand_dims(input_tensor, axis=0) # 添加batch维度 input_tensor /= 255.0 # 归一化 start_time = time.perf_counter() # ONNX Runtime推理 outputs = quant_session.run( None, {'images': input_tensor} ) quant_time = time.perf_counter() - start_time quant_total_time += quant_time # 后处理 (示例,需根据实际输出调整) # 这里简化为使用YOLO自带的后处理方法 quant_results = model.predict( source=img, # 使用原始图像 verbose=False ) # 保存检测结果图片 normal_plot = normal_results[0].plot() quant_plot = quant_results[0].plot() normal_save_path = f"./res/normal/{file_name}" quant_save_path = f"./res/quant/{file_name}" cv2.imwrite(normal_save_path, normal_plot) cv2.imwrite(quant_save_path, quant_plot) if i % 10 == 0: # 每10张打印一次 print(f"[{file_name}] 原始: {normal_time:.4f}s | 量化: {quant_time:.4f}s") 计算平均速度 avg_normal_time = normal_total_time / len(all_files) avg_quant_time = quant_total_time / len(all_files) 输出推理速度 print(“\n” + “=” * 40) print(f"{‘测试统计’:^40}“) print(”=" * 40) print(f"测试图片总数: {len(all_files)}“) print(f"原始模型平均推理时间: {avg_normal_time:.6f} 秒/张”) print(f"量化模型平均推理时间: {avg_quant_time:.6f} 秒/张") print(f"原始模型总耗时: {normal_total_time:.4f} 秒") print(f"量化模型总耗时: {quant_total_time:.4f} 秒") print(f"速度提升: {(avg_normal_time - avg_quant_time) / avg_normal_time * 100:.2f}%“) print(”=" * 40)
08-22
import os import cv2 from PIL import Image from tqdm import tqdm import numpy as np import queue import threading import onnxruntime as ort os.environ["CUDA_VISIBLE_DEVICES"] = "0" class Videocap: def __init__(self, video, model_name, limit=1280): self.model_name = model_name vid = cv2.VideoCapture(video) width = int(vid.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(vid.get(cv2.CAP_PROP_FRAME_HEIGHT)) self.total = int(vid.get(cv2.CAP_PROP_FRAME_COUNT)) self.fps = vid.get(cv2.CAP_PROP_FPS) self.ori_width, self.ori_height = width, height max_edge = max(width, height) scale_factor = limit / max_edge if max_edge > limit else 1. height = int(round(height * scale_factor)) width = int(round(width * scale_factor)) self.width, self.height = self.to_8s(width), self.to_8s(height) self.count = 0 self.cap = vid self.ret, frame = self.cap.read() self.cap.set(cv2.CAP_PROP_POS_FRAMES, 0) self.q = queue.Queue(maxsize=100) t = threading.Thread(target=self._reader) t.daemon = True t.start() def _reader(self): while True: self.ret, frame = self.cap.read() if not self.ret: break frame = np.asarray(self.process_frame(frame, self.width, self.height)) self.q.put(frame) self.count += 1 self.cap.release() def read(self): f = self.q.get() self.q.task_done() return f def to_8s(self, x): if 'tiny' in self.model_name: return 256 if x < 256 else x - x % 16 else: return 256 if x < 256 else x - x % 8 def process_frame(self, img, width, height): img = Image.fromarray(img[:, :, ::-1]).resize((width, height), Image.Resampling.BILINEAR) img = np.array(img).astype(np.float32) / 127.5 - 1.0 return np.expand_dims(img, axis=0) class Cartoonizer(): def __init__(self, model_path, device="gpu"): self.model_path = model_path self.device = device self.name = os.path.basename(model_path).rsplit('.', 1)[0] if ort.get_device() == 'GPU' and device == "gpu": self.sess_land = ort.InferenceSession(model_path, providers=['CUDAExecutionProvider', 'CPUExecutionProvider']) else: self.sess_land = ort.InferenceSession(model_path, providers=['CPUExecutionProvider']) def post_precess(self, img, wh): img = (img.squeeze() + 1.) / 2 * 255 img = img.clip(0, 255).astype(np.uint8) img = Image.fromarray(img).resize((wh[0], wh[1]), Image.Resampling.BILINEAR) img = np.array(img).astype(np.uint8) return img def process_video(self, video_path, output_path): vid = Videocap(video_path, self.name) codec = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') num = vid.total video_out = cv2.VideoWriter(output_path, codec, vid.fps, (vid.ori_width, vid.ori_height)) pbar = tqdm(total=vid.total) pbar.set_description(f"Processing video: {os.path.basename(video_path)}") while num > 0: if vid.count < vid.total and not vid.ret and vid.q.empty(): pbar.close() video_out.release() print(f"Warning: Video might be broken: {video_path}") return output_path frame = vid.read() fake_img = self.sess_land.run(None, {self.sess_land.get_inputs()[0].name: frame})[0] fake_img = self.post_precess(fake_img, (vid.ori_width, vid.ori_height)) video_out.write(fake_img[:, :, ::-1]) pbar.update(1) num -= 1 pbar.close() video_out.release() return output_path def process_image(self, image_path, output_path): img = cv2.imread(image_path) if img is None: print(f"Error reading image: {image_path}") return None ori_height, ori_width = img.shape[:2] # Calculate target size max_edge = max(ori_width, ori_height) scale_factor = 1280 / max_edge if max_edge > 1280 else 1. height = int(round(ori_height * scale_factor)) width = int(round(ori_width * scale_factor)) if 'tiny' in self.name: width = 256 if width < 256 else width - width % 16 height = 256 if height < 256 else height - height % 16 else: width = 256 if width < 256 else width - width % 8 height = 256 if height < 256 else height - height % 8 # Preprocess image img_rgb = Image.fromarray(img[:, :, ::-1]).resize((width, height), Image.Resampling.BILINEAR) img_np = np.array(img_rgb).astype(np.float32) / 127.5 - 1.0 input_data = np.expand_dims(img_np, axis=0) # Run model fake_img = self.sess_land.run(None, {self.sess_land.get_inputs()[0].name: input_data})[0] # Post-process result_img = self.post_precess(fake_img, (ori_width, ori_height)) # Save result cv2.imwrite(output_path, result_img[:, :, ::-1]) return output_path def videopic_to_new(params): """ 将输入目录中的图片视频转换为动漫风格 参数: params (dict): 包含以下键的字典: "video_dir": 输入目录路径 "model": ONNX模型文件路径 "output_dir": 输出目录路径 "device": (可选) 运行设备 ("cpu" 或 "gpu"),默认为 "gpu" """ # 从参数中提取值 input_dir = params["video_dir"] model_path = params["model"] output_dir = params["output_dir"] device = params.get("device", "gpu") # 确保输出目录存在 os.makedirs(output_dir, exist_ok=True) # 初始化卡通化器 cartoonizer = Cartoonizer(model_path, device) model_name = os.path.basename(model_path).rsplit('.', 1)[0] # 支持的媒体格式 image_exts = ['.png', '.jpg', '.jpeg', '.bmp', '.tiff', '.webp'] video_exts = ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv'] # 处理所有文件 processed_files = [] for filename in os.listdir(input_dir): filepath = os.path.join(input_dir, filename) if not os.path.isfile(filepath): continue ext = os.path.splitext(filename)[1].lower() output_name = f"{os.path.splitext(filename)[0]}_{model_name}{ext}" output_path = os.path.join(output_dir, output_name) try: if ext in image_exts: print(f"\nProcessing image: {filename}") result = cartoonizer.process_image(filepath, output_path) if result: processed_files.append(result) print(f"Saved: {output_name}") elif ext in video_exts: print(f"\nProcessing video: {filename}") result = cartoonizer.process_video(filepath, output_path) if result: processed_files.append(result) print(f"Saved: {output_name}") except Exception as e: print(f"Error processing {filename}: {str(e)}") print("\nProcessing completed.") print(f"Total files processed: {len(processed_files)}") return processed_files if __name__ == "__main__": # 构建参数字典 params = { "video_dir": r"E:\软件视频类型测试\1带货测试\成品", "model": r"E:\python成品\15视频转绘\AnimeGANv3-1.1.0\AnimeGANv3-1.1.0\deploy\AnimeGANv3_Hayao_36.onnx", "output_dir": r"E:\软件视频类型测试\1带货测试\成品\成品", "device": "gpu" # 可选,默认为gpu } # 执行转换 results = videopic_to_new(params) # 打印结果 print("\nProcessed files:") for res in results: print(f" - {res}") 为什么已经选择了gpu 但是任务管理中可以看到gpu并没有启用
06-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值