如何提升Python屏幕颜色检测点击脚本的响应速度至0.1ms以内?
优化特定颜色检测与点击脚本至0.1ms以下响应时间的方案
你的当前脚本瓶颈主要在pyautogui跨平台封装的像素检测开销、循环内冗余按键检查以及旧版鼠标事件API上,以下是针对性的优化方案,可大幅压缩响应时间:
1. 替换pyautogui像素检测为Windows原生API
pyautogui的pixelMatchesColor为了兼容多平台做了大量封装,性能远不如直接调用Windows GDI API。用ctypes直接调用GetDC和GetPixel,能把像素检测耗时砍半:
import ctypes from ctypes import wintypes user32 = ctypes.WinDLL('user32', use_last_error=True) gdi32 = ctypes.WinDLL('gdi32', use_last_error=True) # 配置API参数类型 user32.GetDC.restype = wintypes.HDC user32.ReleaseDC.restype = wintypes.BOOL user32.ReleaseDC.argtypes = (wintypes.HWND, wintypes.HDC) gdi32.GetPixel.restype = wintypes.COLORREF gdi32.GetPixel.argtypes = (wintypes.HDC, ctypes.c_int, ctypes.c_int) def get_pixel_color(x, y): hdc = user32.GetDC(None) # 获取全屏设备上下文 color = gdi32.GetPixel(hdc, x, y) user32.ReleaseDC(None, hdc) # 转换Windows COLORREF格式(0x00BBGGRR)为RGB return (color & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF) def pixel_matches_color(x, y, target_rgb, tolerance=0): r, g, b = get_pixel_color(x, y) tr, tg, tb = target_rgb return (abs(r - tr) <= tolerance and abs(g - tg) <= tolerance and abs(b - tb) <= tolerance)
2. 用SendInput替代mouse_event实现低延迟点击
mouse_event是已废弃的旧API,SendInput是Windows官方推荐的输入模拟接口,延迟更低且更稳定,同时去掉无用的time.sleep(0.00):
def click(x, y): # 直接设置光标位置 user32.SetCursorPos(x, y) INPUT_MOUSE = 0 MOUSEEVENTF_LEFTDOWN = 0x0002 MOUSEEVENTF_LEFTUP = 0x0004 # 定义输入事件结构体 class MOUSEINPUT(ctypes.Structure): _fields_ = (("dx", ctypes.c_long), ("dy", ctypes.c_long), ("mouseData", ctypes.c_ulong), ("dwFlags", ctypes.c_ulong), ("time", ctypes.c_ulong), ("dwExtraInfo", ctypes.POINTER(ctypes.c_ulong))) class INPUT(ctypes.Structure): _fields_ = (("type", ctypes.c_ulong), ("mi", MOUSEINPUT)) # 构造按下和抬起事件 down_input = INPUT(type=INPUT_MOUSE, mi=MOUSEINPUT(dx=0, dy=0, mouseData=0, dwFlags=MOUSEEVENTF_LEFTDOWN, time=0, dwExtraInfo=None)) up_input = INPUT(type=INPUT_MOUSE, mi=MOUSEINPUT(dx=0, dy=0, mouseData=0, dwFlags=MOUSEEVENTF_LEFTUP, time=0, dwExtraInfo=None)) # 发送输入事件 user32.SendInput(1, ctypes.byref(down_input), ctypes.sizeof(INPUT)) user32.SendInput(1, ctypes.byref(up_input), ctypes.sizeof(INPUT))
3. 优化循环逻辑,减少冗余按键检查
keyboard.is_pressed每次调用都会触发系统调用,开销不小。用线程单独监听q键按下事件,主线程专注像素检测和点击,避免循环内的冗余检查:
import threading stop_flag = False def listen_for_stop(): global stop_flag keyboard.wait('q') stop_flag = True # 启动后台监听线程 threading.Thread(target=listen_for_stop, daemon=True).start() # 主线程循环 while not stop_flag: if pixel_matches_color(893, 496, (113, 109, 51), tolerance=51): click(893, 496)
4. 额外优化:用JIT编译加速颜色检查
如果上述优化仍达不到0.1ms,可以用numba将颜色检查函数编译为机器码,进一步降低Python解释器开销:
from numba import jit @jit(nopython=True) def check_color(r, g, b, tr, tg, tb, tolerance): return (abs(r - tr) <= tolerance and abs(g - tg) <= tolerance and abs(b - tb) <= tolerance) # 修改pixel_matches_color调用JIT函数 def pixel_matches_color(x, y, target_rgb, tolerance=0): r, g, b = get_pixel_color(x, y) tr, tg, tb = target_rgb return check_color(r, g, b, tr, tg, tb, tolerance)
整合后的完整代码
import ctypes from ctypes import wintypes import threading import keyboard from numba import jit user32 = ctypes.WinDLL('user32', use_last_error=True) gdi32 = ctypes.WinDLL('gdi32', use_last_error=True) # 初始化API参数类型 user32.GetDC.restype = wintypes.HDC user32.ReleaseDC.restype = wintypes.BOOL user32.ReleaseDC.argtypes = (wintypes.HWND, wintypes.HDC) gdi32.GetPixel.restype = wintypes.COLORREF gdi32.GetPixel.argtypes = (wintypes.HDC, ctypes.c_int, ctypes.c_int) user32.SetCursorPos.argtypes = (ctypes.c_int, ctypes.c_int) user32.SendInput.argtypes = (ctypes.c_uint, ctypes.POINTER(ctypes.c_void_p), ctypes.c_int) # JIT编译颜色检查函数 @jit(nopython=True) def check_color(r, g, b, tr, tg, tb, tolerance): return (abs(r - tr) <= tolerance and abs(g - tg) <= tolerance and abs(b - tb) <= tolerance) def get_pixel_color(x, y): hdc = user32.GetDC(None) color = gdi32.GetPixel(hdc, x, y) user32.ReleaseDC(None, hdc) return (color & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF) def pixel_matches_color(x, y, target_rgb, tolerance=0): r, g, b = get_pixel_color(x, y) tr, tg, tb = target_rgb return check_color(r, g, b, tr, tg, tb, tolerance) def click(x, y): user32.SetCursorPos(x, y) INPUT_MOUSE = 0 MOUSEEVENTF_LEFTDOWN = 0x0002 MOUSEEVENTF_LEFTUP = 0x0004 class MOUSEINPUT(ctypes.Structure): _fields_ = (("dx", ctypes.c_long), ("dy", ctypes.c_long), ("mouseData", ctypes.c_ulong), ("dwFlags", ctypes.c_ulong), ("time", ctypes.c_ulong), ("dwExtraInfo", ctypes.POINTER(ctypes.c_ulong))) class INPUT(ctypes.Structure): _fields_ = (("type", ctypes.c_ulong), ("mi", MOUSEINPUT)) down_input = INPUT(type=INPUT_MOUSE, mi=MOUSEINPUT(dx=0, dy=0, mouseData=0, dwFlags=MOUSEEVENTF_LEFTDOWN, time=0, dwExtraInfo=None)) up_input = INPUT(type=INPUT_MOUSE, mi=MOUSEINPUT(dx=0, dy=0, mouseData=0, dwFlags=MOUSEEVENTF_LEFTUP, time=0, dwExtraInfo=None)) user32.SendInput(1, ctypes.byref(down_input), ctypes.sizeof(INPUT)) user32.SendInput(1, ctypes.byref(up_input), ctypes.sizeof(INPUT)) stop_flag = False def listen_for_stop(): global stop_flag keyboard.wait('q') stop_flag = True threading.Thread(target=listen_for_stop, daemon=True).start() while not stop_flag: if pixel_matches_color(893, 496, (113, 109, 51), tolerance=51): click(893, 496)
这些优化组合后,响应时间应该能稳定压到0.1ms以下。核心思路是尽可能绕过Python层面的跨平台封装,直接调用Windows原生API,同时减少循环内的冗余系统调用,用JIT编译加速计算逻辑。
内容的提问来源于stack exchange,提问作者Poro KGB
相关产品推荐
相关产品推荐

