基于YoloV11和驱动级鼠标模拟实现Ai自瞄
本文将围绕基于 YoloV11 和驱动级鼠标实现 FPS 游戏 AI 自瞄展开阐述。
需要着重强调的是,本文内容仅用于学术研究和技术学习目的。严禁任何个人或组织将文中所提及的技术、方法及思路应用于违法行为,包括但不限于在各类游戏中实施作弊等违规操作。若因违反此声明而产生的一切法律后果,均与本文作者无关。
一、原理
AI 自瞄是一种借助人工智能技术自动控制瞄准目标的功能,在 FPS(第一人称射击)游戏场景中,基于目标检测算法(如 YOLO 系列)和驱动级模拟鼠标来实现 AI 自瞄
- 图像采集
- 游戏画面截取:要实现 AI 自瞄,首先需要获取游戏画面信息。一般通过屏幕截图的方式来完成,在计算机系统层面,利用相关的图形 API(如 Windows 系统下的 GDI、DirectX 等)可以截取游戏窗口内的图像。截取到的画面将作为后续目标检测算法的输入数据。
- 实时性要求:为了保证自瞄的及时性和准确性,图像采集需要具备较高的帧率,通常每秒要截取数十帧甚至上百帧的画面,以确保能够实时捕捉游戏中目标的动态变化。
- 目标检测
- 特征提取与模型训练:目标检测是 AI 自瞄的核心环节之一。以 YOLO(You Only Look Once)系列算法为例,其基本思想是将输入的图像划分为多个网格,然后通过卷积神经网络(CNN)对每个网格进行特征提取。在训练阶段,使用大量包含目标对象(如游戏中的敌人)的图像数据进行训练,让模型学习目标的特征和位置信息。训练好的模型能够识别出图像中目标的类别和位置。
- 目标定位:在实际应用中,将采集到的游戏画面输入到训练好的目标检测模型中,模型会输出目标在图像中的位置信息,通常以边界框(bounding box)的形式表示,包含目标的左上角和右下角坐标,从而确定目标在画面中的具体位置。
- 坐标转换
- 图像坐标到屏幕坐标:目标检测模型输出的是目标在图像中的坐标,而要实现鼠标的自动瞄准,需要将这些图像坐标转换为屏幕上的实际坐标。这需要考虑图像在屏幕上的位置、缩放比例等因素。通过一定的数学变换公式,可以将图像坐标映射到屏幕坐标,从而确定目标在屏幕上的具体位置。
- 分辨率适配:不同的游戏和显示器可能具有不同的分辨率,因此在进行坐标转换时,需要对不同的分辨率进行适配,确保在各种分辨率下都能准确地将目标的图像坐标转换为屏幕坐标。
- 驱动级模拟鼠标
- 鼠标控制原理:驱动级模拟鼠标是实现 AI 自瞄的关键步骤。在操作系统层面,鼠标的移动和点击操作是通过向系统发送特定的输入信号来实现的。驱动级模拟鼠标可以绕过游戏的输入检测机制,直接向操作系统发送鼠标控制信号,从而实现鼠标的自动移动和点击。
- 精准控制:根据目标在屏幕上的坐标,计算出鼠标需要移动的距离和方向,然后通过驱动级模拟鼠标技术,精确地控制鼠标移动到目标位置。同时,还可以根据游戏的实际情况,模拟鼠标的点击操作,实现自动射击。
实时反馈与调整 - 动态跟踪:在游戏中,目标对象通常是动态移动的,因此 AI 自瞄系统需要实时跟踪目标的位置变化。通过不断地采集游戏画面、进行目标检测和坐标转换,系统可以实时获取目标的最新位置信息,并及时调整鼠标的移动方向和距离,确保始终瞄准目标。
- 误差修正:由于各种因素的影响,如网络延迟、图像采集误差等,可能会导致目标检测和坐标转换出现一定的误差。为了提高自瞄的准确性,系统需要具备误差修正机制,通过不断地反馈和调整,减小误差,使鼠标能够更加精准地瞄准目标。
二、代码实现
1.实现图像识别
- 实时获取游戏图像
- 使用Mss截图方式,提高截图速度,并使用多线程加快截图和图像检测的速度
-
import timeimport threadingimport mssimport numpy as npimport cv2import threadingdef screenshot_thread(width, height, shift_x, screenshot_interval, lock, latest_screenshot):last_screenshot_time = time.time()with mss.mss() as sct:monitor = sct.monitors[0]start_x = (monitor["width"] - width) // 2 + shift_xstart_y = (monitor["height"] - height) // 2monitor_area = {"left": start_x,"top": start_y,"width": width,"height": height}while True:current_time = time.time()if current_time - last_screenshot_time > screenshot_interval:try:sct_img = sct.grab(monitor_area)screenshot_np = np.array(sct_img)screenshot_np = cv2.cvtColor(screenshot_np, cv2.COLOR_BGRA2BGR)with lock:latest_screenshot = screenshot_nplast_screenshot_time = current_timeexcept Exception as e:print(f"截图时发生错误: {e}")time.sleep(0.001)
- 目标检测
- 使用本地已训练好的模型进行检测,并将检测结果显示在一个框内
- 考虑到部分游戏全屏后会出现游戏画面默认置顶的情况,所以我们使用win32模块将小窗口强制置顶在游戏画面之上,便于我们观察
-
import timeimport cv2import numpy as npimport win32guiimport win32conimport mssfrom ultralytics import YOLOdef detect_and_process(model, width, height, shift_x, window_name, lock, latest_screenshot, target_center_coordinates,shift_pressed, coordinate_smoother, logitech):history_boxes = []history_confidences = []history_size = 5topmost_interval = 1last_topmost_time = time.time()with mss.mss() as sct:monitor = sct.monitors[0]start_x = (monitor["width"] - width) // 2 + shift_xstart_y = (monitor["height"] - height) // 2while True:current_time = time.time()if current_time - last_topmost_time > topmost_interval:hwnd = win32gui.FindWindow(None, window_name)if hwnd != 0:win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)last_topmost_time = current_timewith lock:if latest_screenshot is None:continuescreenshot_np = latest_screenshot.copy()try:results = model(screenshot_np, verbose=False, half=True)except Exception as e:print(f"目标检测时发生错误: {e}")continuemax_conf = 0best_box = Nonedrawn_y_ranges = []for result in results:boxes = result.boxes.cpu().numpy()for box in boxes:x1, y1, x2, y2 = box.xyxy[0].astype(int)is_overlap = any(y1 < y2_ and y2 > y1_ for y1_, y2_ in drawn_y_ranges)if is_overlap:continueconf = box.conf[0]history_confidences.append(conf)if len(history_confidences) > history_size:history_confidences.pop(0)smoothed_conf = np.mean(history_confidences)if smoothed_conf > max_conf:max_conf = smoothed_confbest_box = boxdrawn_y_ranges.append((y1, y2))result_image = screenshot_np.copy()if best_box is not None:x1, y1, x2, y2 = best_box.xyxy[0].astype(int)current_box = np.array([x1, y1, x2, y2])history_boxes.append(current_box)if len(history_boxes) > history_size:history_boxes.pop(0)avg_box = np.mean(history_boxes, axis=0).astype(int)x1, y1, x2, y2 = avg_boxcls = int(best_box.cls[0])class_name = results[0].names[cls]conf = max_confcv2.rectangle(result_image, (x1, y1), (x2, y2), (0, 255, 0), 2)label = f'{class_name}: {conf:.2f}'cv2.putText(result_image, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)x_center = (x1 + x2) // 2y_center = (y1 + y2) // 2screen_x_center = start_x + x_centerscreen_y_center = start_y + y_centertarget_center_coordinates.append((screen_x_center, screen_y_center))if len(target_center_coordinates) > 100:target_center_coordinates.pop(0)if shift_pressed:smoothed_x, smoothed_y = coordinate_smoother.smooth_coordinate(screen_x_center, screen_y_center)logitech.mouse_move((smoothed_x, smoothed_y))cv2.imshow(window_name, result_image)if cv2.waitKey(1) & 0xFF == ord('q'):break
- 目标敌人的坐标
- 我们以屏幕左上角定为坐标(0,0)鼠标坐标为屏幕中心(960,540)实时获取目标中心的坐标点,计算鼠标到目标坐标点的x,y轴距离,转化为数值存储在一个数组中,便于鼠标移动模块实时调用
-
target_center_coordinates = []def store_target_center_coordinates(x_center, y_center):"""存储目标中心坐标点,并控制列表长度不超过 100:param x_center: 目标中心的 x 坐标:param y_center: 目标中心的 y 坐标"""target_center_coordinates.append((x_center, y_center))if len(target_center_coordinates) > 100:target_center_coordinates.pop(0)def get_target_center_coordinates():"""获取存储的目标中心坐标点列表:return: 目标中心坐标点列表"""return target_center_coordinates
- 将以上的图像识别并输出坐标制作成一个py文件,封装成一个目标检测模块
-
import numpy as npimport cv2from ultralytics import YOLOimport win32guiimport win32conimport timeimport threadingimport mssimport osfrom pynput import keyboardimport ctypesimport pyautoguiimport torch# PID 控制器类class PID:def __init__(self, P=0.2, I=0.01, D=0.1):self.kp, self.ki, self.kd = P, I, Dself.uPrevious, self.uCurent = 0, 0self.setValue, self.lastErr, self.errSum = 0, 0, 0self.errSumLimit = 10def pidPosition(self, setValue, curValue):err = setValue - curValuedErr = err - self.lastErrself.errSum += erroutPID = self.kp * err + self.ki * self.errSum + self.kd * dErrself.lastErr = errreturn outPID# 罗技驱动类class LOGITECH:def __init__(self):self.dll = Noneself.state = Falseself.load_dll()def load_dll(self):try:dll_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logitech.driver.dll')self.dll = ctypes.CDLL(dll_path)self.dll.device_open.restype = ctypes.c_intresult = self.dll.device_open()self.state = (result == 1)self.dll.moveR.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_bool]self.dll.moveR.restype = Noneexcept FileNotFoundError:print(f'错误, 找不到 DLL 文件')except OSError as e:print(f'错误, 加载 DLL 文件失败: {e}')def mouse_move(self, end_xy, min_xy=2):if not self.state:returnend_x, end_y = end_xypid_x = PID()pid_y = PID()new_x, new_y = pyautogui.position()move_x = pid_x.pidPosition(end_x, new_x)move_y = pid_y.pidPosition(end_y, new_y)move_x = np.clip(move_x, -min_xy if move_x < 0 else min_xy, None).astype(int)move_y = np.clip(move_y, -min_xy if move_y < 0 else min_xy, None).astype(int)self.dll.moveR(move_x, move_y, True)# 平滑坐标的函数,使用简单移动平均class CoordinateSmoother:def __init__(self, window_size=5):self.window_size = window_sizeself.x_buffer = []self.y_buffer = []def smooth_coordinate(self, x, y):self.x_buffer.append(x)self.y_buffer.append(y)if len(self.x_buffer) > self.window_size:self.x_buffer.pop(0)self.y_buffer.pop(0)smoothed_x = int(np.mean(self.x_buffer))smoothed_y = int(np.mean(self.y_buffer))return smoothed_x, smoothed_y# 全局变量target_center_coordinates = []latest_screenshot = Nonelock = threading.Lock()logitech = LOGITECH()coordinate_smoother = CoordinateSmoother()shift_pressed = False# 初始化模型和窗口def init_model_and_window(model_path, window_name, width, height, shift_x):model_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), model_path)if not os.path.exists(model_path):print(f"模型文件 {model_path} 不存在,请检查。")return None, Nonemodel = YOLO(model_path)model.fuse()device = 'cuda' if torch.cuda.is_available() else 'cpu'model.to(device)cv2.namedWindow(window_name, cv2.WINDOW_NORMAL)cv2.resizeWindow(window_name, width, height)time.sleep(0.1)hwnd = win32gui.FindWindow(None, window_name)win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)return model, hwnd# 截图线程函数def screenshot_thread(width, height, shift_x, screenshot_interval):global latest_screenshotlast_screenshot_time = time.time()with mss.mss() as sct:monitor = sct.monitors[0]start_x = (monitor["width"] - width) // 2 + shift_xstart_y = (monitor["height"] - height) // 2monitor_area = {"left": start_x,"top": start_y,"width": width,"height": height}while True:current_time = time.time()if current_time - last_screenshot_time > screenshot_interval:try:sct_img = sct.grab(monitor_area)screenshot_np = np.array(sct_img)screenshot_np = cv2.cvtColor(screenshot_np, cv2.COLOR_BGRA2BGR)with lock:latest_screenshot = screenshot_nplast_screenshot_time = current_timeexcept Exception as e:print(f"截图时发生错误: {e}")time.sleep(0.001)# 实时存放目标中心坐标点的函数def store_target_center_coordinates(x_center, y_center):global target_center_coordinatestarget_center_coordinates.append((x_center, y_center))if len(target_center_coordinates) > 100:target_center_coordinates.pop(0)# 目标检测和处理函数def detect_and_process(model, width, height, shift_x, window_name):history_boxes = []history_confidences = []history_size = 5topmost_interval = 1last_topmost_time = time.time()with mss.mss() as sct:monitor = sct.monitors[0]start_x = (monitor["width"] - width) // 2 + shift_xstart_y = (monitor["height"] - height) // 2while True:current_time = time.time()if current_time - last_topmost_time > topmost_interval:hwnd = win32gui.FindWindow(None, window_name)if hwnd != 0:win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)last_topmost_time = current_timewith lock:if latest_screenshot is None:continuescreenshot_np = latest_screenshot.copy()try:results = model(screenshot_np, verbose=False, half=True)except Exception as e:print(f"目标检测时发生错误: {e}")continuemax_conf = 0best_box = Nonedrawn_y_ranges = []for result in results:boxes = result.boxes.cpu().numpy()for box in boxes:x1, y1, x2, y2 = box.xyxy[0].astype(int)is_overlap = any(y1 < y2_ and y2 > y1_ for y1_, y2_ in drawn_y_ranges)if is_overlap:continueconf = box.conf[0]history_confidences.append(conf)if len(history_confidences) > history_size:history_confidences.pop(0)smoothed_conf = np.mean(history_confidences)if smoothed_conf > max_conf:max_conf = smoothed_confbest_box = boxdrawn_y_ranges.append((y1, y2))result_image = screenshot_np.copy()if best_box is not None:x1, y1, x2, y2 = best_box.xyxy[0].astype(int)current_box = np.array([x1, y1, x2, y2])history_boxes.append(current_box)if len(history_boxes) > history_size:history_boxes.pop(0)avg_box = np.mean(history_boxes, axis=0).astype(int)x1, y1, x2, y2 = avg_boxcls = int(best_box.cls[0])class_name = results[0].names[cls]conf = max_confcv2.rectangle(result_image, (x1, y1), (x2, y2), (0, 255, 0), 2)label = f'{class_name}: {conf:.2f}'cv2.putText(result_image, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)x_center = (x1 + x2) // 2y_center = (y1 + y2) // 2screen_x_center = start_x + x_centerscreen_y_center = start_y + y_centerstore_target_center_coordinates(screen_x_center, screen_y_center)if shift_pressed:smoothed_x, smoothed_y = coordinate_smoother.smooth_coordinate(screen_x_center, screen_y_center)logitech.mouse_move((smoothed_x, smoothed_y))cv2.imshow(window_name, result_image)if cv2.waitKey(1) & 0xFF == ord('q'):break# 封装获取目标中心坐标的函数def get_target_center_coordinates():global target_center_coordinatesreturn target_center_coordinates# 键盘事件处理函数def on_press(key):global shift_pressedif key == keyboard.Key.shift:shift_pressed = Truedef on_release(key):global shift_pressedif key == keyboard.Key.shift:shift_pressed = Falseif key == keyboard.Key.esc:return Falsedef main():model_path = 'best.pt'window_name = 'Detection Result'width, height = 320, 320shift_x = 120screenshot_interval = 0.1import torch # 导入 torch 库model, hwnd = init_model_and_window(model_path, window_name, width, height, shift_x)if model is None:returnscreenshot_t = threading.Thread(target=screenshot_thread, args=(width, height, shift_x, screenshot_interval))screenshot_t.daemon = Truescreenshot_t.start()keyboard_listener = keyboard.Listener(on_press=on_press, on_release=on_release)keyboard_listener.start()try:detect_and_process(model, width, height, shift_x, window_name)except KeyboardInterrupt:print("程序被用户手动中断。")except Exception as e:print(f"程序运行过程中发生错误: {e}")finally:cv2.destroyAllWindows()keyboard_listener.stop()print("存储的目标中心坐标点:", get_target_center_coordinates())if __name__ == "__main__":main()
-
注意:一定要安装python所需的依赖库,最好是在虚拟环境中运行(如Anaconda)
2.驱动级鼠标移动
-
import osimport ctypesimport pyautoguiimport timefrom math import sqrtfrom screenshot import get_target_center_coordinatesfrom pynput import keyboardimport tkinter as tkfrom tkinter import ttkclass PID:def __init__(self, P=2.0, I=0.02, D=0.5): # 增大 P 值以加快响应速度self.kp, self.ki, self.kd = P, I, Dself.uPrevious, self.uCurent = 0, 0self.setValue, self.lastErr, self.errSum = 0, 0, 0self.errSumLimit = 10def pidPosition(self, setValue, curValue):err = setValue - curValuedErr = err - self.lastErrself.errSum += erroutPID = self.kp * err + self.ki * self.errSum + self.kd * dErrself.lastErr = errreturn outPIDclass LOGITECH:def __init__(self):self.dll = Noneself.state = Falseself.load_dll()def load_dll(self):try:file_path = os.path.abspath(os.path.dirname(__file__))self.dll = ctypes.CDLL(f'{file_path}/logitech.driver.dll')self.dll.device_open.restype = ctypes.c_intresult = self.dll.device_open()self.state = (result == 1)self.dll.moveR.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_bool]self.dll.moveR.restype = Noneexcept FileNotFoundError:print(f'错误, 找不到 DLL 文件')except OSError as e:print(f'错误, 加载 DLL 文件失败: {e}')def mouse_move(self, end_xy, min_xy=0.5, distance_threshold=5, max_x_move=500, max_y_move=400):if not self.state:returnend_x, end_y = end_xynew_x, new_y = pyautogui.position()# 计算目标坐标与当前鼠标坐标的距离distance = sqrt((end_x - new_x) ** 2 + (end_y - new_y) ** 2)print(f"目标坐标与当前鼠标坐标的距离: {distance}")# 如果距离小于阈值,不进行移动if distance < distance_threshold:print("距离小于阈值,不进行移动")returnpid_x = PID(P=sensitivity)pid_y = PID(P=sensitivity)move_x = pid_x.pidPosition(end_x, new_x)move_y = pid_y.pidPosition(end_y, new_y)# 限制 x 轴移动范围move_x = max(-max_x_move, min(max_x_move, move_x))# 限制 y 轴移动范围move_y = max(-max_y_move, min(max_y_move, move_y))move_x = max(min_xy, move_x) if move_x > 0 else min(-min_xy, move_x) if move_x < 0 else int(move_x)move_y = max(min_xy, move_y) if move_y > 0 else min(-min_xy, move_y) if move_y < 0 else int(move_y)move_x = int(move_x)move_y = int(move_y)print(f"传递给 moveR 的参数: x={move_x}, y={move_y}")result = self.dll.moveR(move_x, move_y, True)print(f"moveR 函数的返回值: {result}")logitech = LOGITECH()aiming = False # 新增状态变量,用于跟踪是否正在瞄准sensitivity = 2.0 # 初始化灵敏度def move_mouse_to_coordinate(end_xy):logitech.mouse_move(end_xy)def on_press(key):global aimingtry:if key == keyboard.Key.shift:aiming = True # 按下 Shift 键,开始瞄准except AttributeError:passdef on_release(key):global aimingif key == keyboard.Key.shift:aiming = False # 松开 Shift 键,停止瞄准if key == keyboard.Key.esc:return Falsedef update_sensitivity(value):global sensitivitysensitivity = float(value)print(f"当前灵敏度: {sensitivity}")# 创建 Tkinter 窗口root = tk.Tk()root.title("灵敏度调整")# 创建滑动条sensitivity_scale = ttk.Scale(root, from_=0.1, to=5.0, orient=tk.HORIZONTAL,command=update_sensitivity, value=sensitivity)sensitivity_scale.pack(pady=20)# 启动 Tkinter 窗口的事件循环root.update()root.withdraw() # 隐藏窗口,避免干扰with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:try:while True:if aiming:# 获取目标中心坐标coordinates = get_target_center_coordinates()if coordinates:print(coordinates)# 假设 coordinates 是一个包含 (x, y) 坐标的元组或列表move_mouse_to_coordinate(coordinates)time.sleep(0.05) # 缩短循环时间间隔root.update() # 更新 Tkinter 窗口except KeyboardInterrupt:print("程序已被手动中断,正在退出...")root.destroy() # 关闭 Tkinter 窗口
3.启动文件
- 制作启动文件有利于隐藏其他两个文件的进程,可以有效防止系统检测
-
import subprocessimport osimport sysimport loggingimport ctypes# 配置日志记录logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')# 定义 Windows API 相关常量和函数PROCESS_ALL_ACCESS = 0x1F0FFFTH32CS_SNAPPROCESS = 0x00000002CreateToolhelp32Snapshot = ctypes.windll.kernel32.CreateToolhelp32SnapshotProcess32First = ctypes.windll.kernel32.Process32FirstProcess32Next = ctypes.windll.kernel32.Process32NextOpenProcess = ctypes.windll.kernel32.OpenProcessTerminateProcess = ctypes.windll.kernel32.TerminateProcessCloseHandle = ctypes.windll.kernel32.CloseHandleclass PROCESSENTRY32(ctypes.Structure):_fields_ = [("dwSize", ctypes.c_ulong),("cntUsage", ctypes.c_ulong),("th32ProcessID", ctypes.c_ulong),("th32DefaultHeapID", ctypes.POINTER(ctypes.c_ulong)),("th32ModuleID", ctypes.c_ulong),("cntThreads", ctypes.c_ulong),("th32ParentProcessID", ctypes.c_ulong),("pcPriClassBase", ctypes.c_long),("dwFlags", ctypes.c_ulong),("szExeFile", ctypes.c_char * 260)]def get_script_paths():"""获取 script1.py 和 script2.py 的文件路径"""current_dir = os.path.dirname(os.path.abspath(__file__))script1_path = os.path.join(current_dir, 'detection', 'screenshot.py')script2_path = os.path.join(current_dir, 'detection', 'logihub.py')return script1_path, script2_pathdef run_hidden(script_path):"""以隐藏窗口的方式异步启动 Python 脚本,并尽量隐藏进程"""startupinfo = Noneif sys.platform.startswith('win'):startupinfo = subprocess.STARTUPINFO()startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOWstartupinfo.wShowWindow = subprocess.SW_HIDEtry:process = subprocess.Popen(['python', script_path], startupinfo=startupinfo)logging.info(f"成功启动脚本: {script_path}")# 这里可以添加更复杂的隐藏进程逻辑,比如修改进程的可见性属性等return processexcept FileNotFoundError:logging.error("Python 解释器未找到,请确保 Python 已正确安装并配置到系统环境变量中。")return Noneexcept Exception as e:logging.error(f"启动脚本 {script_path} 时发生其他错误: {e}")return Nonedef main():"""主函数,负责启动两个脚本并等待它们执行完毕"""script1_path, script2_path = get_script_paths()logging.info(f"正在启动 {script1_path} 和 {script2_path}")process1 = run_hidden(script1_path)process2 = run_hidden(script2_path)if process1 and process2:logging.info(f"{script1_path} 和 {script2_path} 已成功启动")try:# 等待两个进程执行完毕process1.wait()process2.wait()logging.info(f"{script1_path} 和 {script2_path} 执行完毕")except Exception as e:logging.error(f"等待进程执行时发生错误: {e}")else:logging.error("启动脚本时出现问题")if __name__ == "__main__":main()
三、开源
此项目已在GitCode平台开源可以使用作者上传的项目直接启动
- 使用Git克隆仓库中的文件
-
git clone https://gitcode.com/2401_86455622/MRAI.git
-
衷心感谢各位读者拨冗阅读本文。若您在阅读过程中发现任何问题,或有相关疑问需要探讨,烦请在评论区留言,我将认真对待每一条反馈并及时予以回应。
相关文章:
基于YoloV11和驱动级鼠标模拟实现Ai自瞄
本文将围绕基于 YoloV11 和驱动级鼠标实现 FPS 游戏 AI 自瞄展开阐述。 需要着重强调的是,本文内容仅用于学术研究和技术学习目的。严禁任何个人或组织将文中所提及的技术、方法及思路应用于违法行为,包括但不限于在各类游戏中实施作弊等违规操作。若因违…...
基于微信小程序的博物馆预约系统的设计与实现
hello hello~ ,这里是 code袁~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 🦁作者简介:一名喜欢分享和记录学习的在校大学生…...
R语言LCMM多维度潜在类别模型流行病学研究:LCA、MM方法分析纵向数据
全文代码数据:https://tecdat.cn/?p39710 在数据分析领域,当我们面对一组数据时,通常会有已知的分组情况,比如不同的治疗组、性别组或种族组等(点击文末“阅读原文”获取完整代码数据)。 然而,…...
python卷积神经网络人脸识别示例实现详解
目录 一、准备 1)使用pytorch 2)安装pytorch 3)准备训练和测试资源 二、卷积神经网络的基本结构 三、代码实现 1)导入库 2)数据预处理 3)加载数据 4)构建一个卷积神经网络 5࿰…...
如何把邮件批量导出到本地
最近遇到邮箱满了的问题,需要把邮件批量导出到本地,然后清空邮箱。 问题是这个邮箱的官网,没有批量导出按钮,比较麻烦;总不能一封一封下载到本地,上万的。 找到了一个好用的工具,Mozilla Thun…...
C++智能指针的使用
文章目录 智能指针的使用和原理智能指针的使用场景RAII和智能指针C标准库智能指针的使用 智能指针的使用和原理 智能指针的使用场景 1. 下面的程序中,new了以后,我们也delete了,但是因为抛异常导致后面的delete没有得到执行,所以…...
Docker安装Redis
一、保证Docker提起来了 systemctl status docker想这没有启动要先启动一下 systemctl status docke二、拉取Redis(默认拉最新版) sudo docker pull redis检查一下拉成功没有 docker images三、创建相关目录 mkdir -p /home/redis/{conf,data}四、…...
深入理解MySQL索引底层数据结构
文章目录 前言一、MySQL索引是什么?二、索引的核心需求三、MySQL为什么选择BTree做为数据结构1.如果使用的是Hash 做为数据结构2.如果使用二叉树做为数据结构3.使用红黑树做为数据结构4.使用B-Tree做为数据结构5.BTree做为数据结构 4.BTree深度剖析结构特性与 B-Tre…...
udp和tcp的区别
目录 UDP 和 TCP 的区别 1. 连接性 2. 可靠性 3. 数据传输顺序 4. 流量控制和拥塞控制 5. 效率 6. 应用场景 UDP 和 TCP 的 C/C 代码实现区别 1. TCP 服务器端和客户端 TCP 服务器端(Server) TCP 客户端(Client) 2. U…...
VMware 虚拟机 ubuntu 20.04 扩容工作硬盘
一、关闭虚拟机 关闭虚拟机参考下图,在vmware 调整磁盘容量 二、借助工具fdisk testubuntu ~ $ df -h Filesystem Size Used Avail Use% Mounted on udev 1.9G 0 1.9G 0% /dev tmpfs 388M 3.1M 385M 1% /run /dev/sda5 …...
MapReduce是什么?
MapReduce 是一种编程模型,最初由 Google 提出,旨在处理大规模数据集。它是分布式计算的一个重要概念,通常用于处理海量数据并进行并行计算。MapReduce的基本思想是将计算任务分解为两个阶段:Map 阶段和 Reduce 阶段。 Map 阶段&a…...
跨越边界,大模型如何助推科技与社会的完美结合?
点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 概述 2024年,大模型技术已成为人工智能领域的焦点。这不仅仅是一项技术进步,更是一次可能深刻影响社会发展方方面面的变革。大模型的交叉能否推动技术与社会的真正融合?2025年…...
计算机毕业设计SpringBoot校园二手交易小程序 校园二手交易平台(websocket消息推送+云存储+双端+数据统计)(源码+文档+运行视频+讲解视频)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
RK3568平台开发系列讲解(ConfigFS篇)ConfigFS核心数据结构
🚀返回专栏总目录 文章目录 一、数据结构二、结构体关系三、案例3.1、configfs_subsystem 实例3.2、config_group 实例化四、属性和方法五、config_item实例化沉淀、分享、成长,让自己和他人都能有所收获!😄 理解 ConfigFS 的核心数据结构对于深入使用和定制 ConfigFS 非…...
【04】RUST特性
文章目录 隐藏shadowing所有权ownership堆区&栈区所有权规则变量&数据Copy Trait与Drop TraitCopy TraitDrop Trait移动克隆函数参数与返回值的所有权参数引用可变引用悬垂引用slice生命周期隐藏shadowing 有点像同名覆盖 let mut guess = String::new();let guess: u3…...
c语言函数学习
C语言函数学习笔记:从入门到实践 一、什么是函数? 函数是C语言中用于封装特定功能的代码块,是模块化编程的核心。通过函数可以实现: 代码复用:避免重复编写相同逻辑 逻辑清晰:将复杂程序分解为多个小模块…...
LSTM的介绍
网上一些描述LSTM文章看的云里雾里,只是介绍LSTM 的结构,并没有说明原理。我这里用通俗易懂的话来描述一下。 我们先来复习一些RNN的核心公式: h t t a n h ( W h h t − 1 W x x t b h ) h_t tanh(W_h h_{t-1} W_x x_t b_h) httan…...
XML DOM
XML DOM XML DOM(Document Object Model)是一种用于访问和操作XML文档的标准方式。它提供了一种树形结构来表示XML文档,使得开发者能够方便地对XML数据进行读取、修改和操作。本文将详细介绍XML DOM的基本概念、结构、操作方法以及应用场景。 一、XML DOM的基本概念 XML …...
认识网络安全
一 网络攻击链 踩点-工具准备-载荷投递-漏洞利用-释放载荷-建立通道-目标达成 简化下: 目标侦察:准确识别目标,收集目标详细信息,比如 网络、 邮箱、员工、社会关系、对外提供服务、漏洞 信息等,为 后续攻击做准备。…...
华为支付-免密支付接入签约代扣场景开发步骤
一、预签约(服务器开发) 1.开发者按照商户模型调用预直连商户预签约或服务商预签约接口获取preSignNo构建签约信息参数contractStr。 为保证支付订单的安全性和可靠性需要对请求body和请求头PayMercAuth对象内的入参排序拼接进行签名。请参考排序拼接和…...
9.JVM-方法区
前言 这次所讲述的是运行时数据区的最后一个部分 从线程共享与否的角度来看 ThreadLocal:如何保证多个线程在并发环境下的安全性?典型应用就是数据库连接管理,以及会话管理 栈、堆、方法区的交互关系 下面就涉及了对象的访问定位 Person&a…...
【Linux Oracle】杂货铺 日常实用2024
1.跨服务器移动文件 passwd=^T^bxxxx `/usr/bin/expect <<-EOF set timeout -1 spawn scp -r ${BATCH_TIME} sxnhtc@192.168.3.x:${EXP_MCRO_DIR}/ expect "*password:" send "$passwd\r" interact expect eof EOF` curl -k -X GET https://192.16…...
深入理解指针初阶:从概念到实践
一、引言 在 C 语言的学习旅程中,指针无疑是一座必须翻越的高峰。它强大而灵活,掌握指针,能让我们更高效地操作内存,编写出更优化的代码。但指针也常常让初学者望而生畏,觉得它复杂难懂。别担心,本文将用通…...
Git 与 Git常用命令
Git 是一个开源的分布式版本控制系统,广泛用于源代码管理。与传统的集中式版本控制系统不同,Git 允许每个开发者在本地拥有完整的代码库副本,支持离线工作和高效的分支管理。每次提交时,Git 会对当前项目的所有文件创建一个快照&a…...
jupyterLab插件开发
jupyter lab安装、配置: jupyter lab安装、配置教程_容器里装jupyterlab-CSDN博客 『Linux笔记』服务器搭建神器JupyterLab_linux_布衣小张-腾讯云开发者社区 Jupyter Lab | 安装、配置、插件推荐、多用户使用教程-腾讯云开发者社区-腾讯云 jupyterLab插件开发教…...
IDEA+DeepSeek让Java开发起飞
1.获取DeepSeek秘钥 登录DeepSeek官网 : https://www.deepseek.com/ 进入API开放平台,第一次需要注册一个账号 进去之后需要创建一个API KEY,然后把APIkey记录保存下来 接着我们获取DeepSeek的API对话接口地址,点击左边的:接口…...
机器学习数学基础:19.线性相关与线性无关
一、线性相关与线性无关的定义 (一)线性相关 想象我们有一组向量,就好比是一群有着不同“力量”和“方向”的小伙伴。给定的向量组 α ⃗ 1 , α ⃗ 2 , ⋯ , α ⃗ m \vec{\alpha}_1, \vec{\alpha}_2, \cdots, \vec{\alpha}_m α 1,α 2…...
快速集成DeepSeek到项目
DeepSeek API-KEY 获取 登录DeekSeek 官网,进入API 开放平台 2. 创建API-KEY 复制API-KEY进行保存,后期API调用使用 项目中集成DeepSeek 这里只展示部分核心代码,具体请查看源码orange-ai-deepseek-biz-starter Slf4j AllArgsConstructo…...
Rocketmq 和 Rabbitmq ,在多消费者的情况下,可以实现顺序消费吗
在多消费者的情况下,RocketMQ 和 RabbitMQ 都可以实现顺序消费,但它们的实现机制和适用场景有所不同。以下是对两者的详细分析和对比: 1. RocketMQ 的顺序消费 1.1 实现机制 顺序消息:RocketMQ 支持顺序消息(Orderly …...
linux下安装【流媒体】SRS之安装与使用
一、 安装srs 这个是一个流媒体服务器。 1.1 github 获取源码 git clone https://github.com/ossrs/srs.git 或者下载国内的 git clone https://gitee.com/ossrs/srs 进去之后下载zip的 #直接使用当前最新的6.0release版本 ,我下载的是zip的 下载了之后上传到…...
Qt QSettings用法
一、概述 QSettings类是Qt框架中的一个重要类,它主要用于存储和访问应用程序的设置和配置。 二、QSettings的构造方式 1、基于组织名和程序名的构造方式(主要用于Windows注册表) 1、explicit QSettings(const QString &organization,c…...
python学opencv|读取图像(六十)先后使用cv2.erode()函数和cv2.dilate()函数实现图像处理
【1】引言 前序学习进程中,先后了解了使用cv2.erode()函数和cv2.dilate()函数实现图像腐蚀和膨胀处理的效果,相关文章链接为: python学opencv|读取图像(五十八)使用cv2.erode()函数实现图像腐蚀处理-CSDN博客 pytho…...
【大数据安全分析】大数据安全分析技术框架与关键技术
在数字化时代,网络安全面临着前所未有的挑战。传统的网络安全防护模式呈现出烟囱式的特点,各个安全防护措施和数据相互孤立,形成了防护孤岛和数据孤岛,难以有效应对日益复杂多变的安全威胁。而大数据分析技术的出现,为…...
[笔记.AI]Deepseek-R1 各参数版本的蒸馏模型对比
备注:信息主要通过Deepseek-R1获得(查询近一个月的在线资料并整理),然后我进行了相应整合。如有错误,希望指出,谢谢。 Deepseek-R1 蒸馏模型 对比维度1.5B7B8B14B32B70B 特有的突破性能力▸ 毫秒级响应(0.3…...
JAVA面向对象2(三大特征)
面向对象的三大特征:封装、继承、多态 封装: 封装,英文单词Encapsulation。 从广义的角度来说,将一块经常要使用的代码片段,定义到方法中,是封装。将多个方法和多个状态数据定义到类体中,也是一…...
Spring Cloud工程完善
目录 完善订单服务 启动类 配置文件 实体类 Controller Service Mapper 测试运行 完成商品服务 启动类 配置文件 实体类 Controller Service Mapper 测试运行 远程调用 需求 实现 1.定义RestTemplate 2.修改order-service中的OrderService 测试运行 Rest…...
AI大模型随机初始化权重并打印网络结构方法(以Deepseekv3为例,单机可跑)
背景 当前大模型的权重加载和调用,主要是通过在HuggingFace官网下载并使用transformer的库来加以实现;其中大模型的权重文件较大(部分>100GB),若只是快速研究网络结构和数据流变化,则无需下载权重。本文…...
介绍下SpringBoot常用的依赖项
Spring Boot 是一个用于快速开发 Spring 应用程序的框架,它通过自动配置和依赖管理简化了开发过程。以下是一些 Spring Boot 项目中常用的依赖项: 1. Spring Boot Starter Web 作用: 用于构建 Web 应用程序,包括 RESTful 服务。依赖项: spr…...
第四节 docker基础之---dockerfile部署JDK
本地宿主机配置jdk 创建test目录: [rootdocker ~]# mkdir test 压缩包tomcat和jdk上传到root/test目录下: 本机部署Jdk 解压jdk: [rootdocker test]# tar -xf jdk-8u211-linux-x64.tar.gz [rootdocker test]# tar -xf apache-tomcat-8.5.…...
Vue基础:index.html、App.vue、main.js三个文件的联系
index.html、App.vue、main.js三个文件的联系 当vue项目npm run dev启动成功后, 浏览器就可以通过路径访问页面,那么这个页面到底展示的是哪个文件里的内容呢? 如果对前端vue有一定的基础知识,这篇文章可忽略。 在vue项目的目录结…...
数据库 绪论
目录 数据库基本概念 一.基本概念 1.信息 2.数据 3.数据库(DB) 4.数据库管理系统(DBMS) 5.数据库系统(DBS) 二.数据管理技术的发展 1.人工管理阶段 2.文件系统阶段 3.数据库系统阶段 4.数据库管…...
26~31.ppt
目录 26.北京主要的景点 题目 解析 27.创新产品展示及说明会 题目 解析 28.《小企业会计准则》 题目 解析 29.学习型社会的学习理念 题目 解析 30.小王-产品展示信息 题目 解析 31.小王-办公理念-信息工作者的每一天 题目 解析 26.北京主要的景点…...
AutoMQ 如何实现没有写性能劣化的极致冷读效率
前言 追赶读(Catch-up Read,冷读)是消息和流系统常见和重要的场景。 削峰填谷:对于消息来说,消息通常用作业务间的解耦和削峰填谷。削峰填谷要求消息队列能将上游发送的数据堆积住,让下游在容量范围内消费…...
启动gateway时Failed to configure a DataSource
问题 在启动网关时候启动失败,报错: 原因很明显,就是没有配制数据库连接信息 实际上是因为在网关模块中导入的某个依赖里面引入了MyBatis的依赖,导致启动的时候自动配置数据库源 但是在这个网关模块中是不需要数据数据库的 解决...
node 程序占用处理方法与后台运行方法
程序占用 如果你在关闭终端后重新运行 node server.js,但提示端口 3000 被占用,说明之前的服务器进程仍然在后台运行。以下是解决方法: 1. 检查后台运行的 Node.js 进程 首先,检查是否有 Node.js 进程正在占用端口 3000。 在 L…...
C# OpenCV机器视觉:对位贴合
在热闹非凡的手机维修街上,阿强开了一家小小的手机贴膜店。每天看着顾客们自己贴膜贴得歪歪扭扭,不是膜的边缘贴不整齐,就是里面充满了气泡,阿强心里就想:“要是我能有个自动贴膜的神器,那该多好啊…...
【计算机网络】TCP/IP 网络模型有哪几层?
目录 应用层 传输层 网络层 网络接口层 总结 为什么要有 TCP/IP 网络模型? 对于同一台设备上的进程间通信,有很多种方式,比如有管道、消息队列、共享内存、信号等方式,而对于不同设备上的进程间通信,就需要网络通…...
本地部署Deepseek R1
使用Ollama open-webui部署Deepseek R1 一、安装Ollama 官网地址:https://ollama.com/,点击下载按钮选择windows版本。并安装 打开命令提示符输入ollama,出现一下提示命令表示ollama安装完成 二、使用Ollama下载deepseek R1不同模型 打开o…...
PHP盲盒商城系统源码 晒图+免签+短信验证+在线回收 thinkphp框架
源码介绍 PHP盲盒商城系统源码 晒图免签短信验证在线回收 thinkphp框架 源码前端uniapp开发,可以打包成APP(非H5封壳)H5,接其他平台支付通道,前后端全开源 H5盲盒首页可以直接开盒新UI 修复优化BUG,修复无…...
[Do374]ansible-nagivator考前整理
[Do374]ansible-nagivator考前整理 1. Ansible-Navigator 升级后的变化1.1 主要变化1.2 重大改变 2. ansible主要配置文件2.1 .ansible-navigator.yml2.2 ansible.cnf 3. 常用模块3.1 file模块3.2 copy模块3.3 user模块和lookup模块3.4 yum和yum_repository模块3.5 systemd和se…...