python 实现屏幕取色

前言

~~其实本来是想要用 pyautogui 写一个自动打音游的脚本(?)
所以采用屏幕取色的办法判断 note
显然这种思路问题太多了,最先遇到的就是取色太慢跟不上的问题~~

取色

有三种方法:

1. PIL 库截图后取色

from PIL import ImageGrab
def getColor1(x, y):
    image = ImageGrab.grab()
    return image.getpixel((x, y))

2. C 标准库里调 gdi32

from ctypes import *
def getColor2(x, y):
    gdi32 = windll.gdi32
    user32 = windll.user32
    hdc = user32.GetDC(None)
    pixel = gdi32.GetPixel(hdc, x, y)
    r = pixel & 0x0000ff
    g = (pixel & 0x00ff00) >> 8
    b = pixel >> 16
    return (r, g, b)

3. pyautogui 自带的取色

import pyautogui
def getColor3(x, y):
    pix = pyautogui.pixel(100, 200)
    return (pix[0], pix[1], pix[2])

测试速度

100 次运行测试
第一种是最慢的,而第二第三种性能差不多,基本都在 0.017s 一次左右。

取色 + 判断点击

试了两种方法。对鼠标所在位置进行判断。

1. 上述最快的取色后 if 判断

def check1():
    x, y = pyautogui.position()
    R, G, B = getColor3(x, y)
    if R <= 100 and G >= 130 and G <=190 and B >= 170 and B <= 220:
        pyautogui.click(x, y)

2. pyautogui 自带的颜色判断

def check2():
    x, y = pyautogui.position()
    if pyautogui.pixelMatchesColor(x, y, (130, 135, 144), tolerance=30): # 这里的 tolerance 是容差
        pyautogui.click(x, y)

测试速度

100 次运行测试 x 3
这个测试并不准确,影响速度的因素很多。移动鼠标时和静止时的耗时都不相同,如果实际触发了点击会导致更慢。
但是综合下来还是第一种速度更快。

多线程

没用,最多压到 0.016s 极限了

咸鱼的完整代码

import time
def countTime(func):
    def wrap(*args, **kw):
        #print('running:', func.__name__)
        start = time.perf_counter()
        func(*args, **kw)
        end = time.perf_counter()
        print('used time:', end - start)
    return wrap

@countTime
def testFunc(func, *args, **kw):
    print ("testing:", func.__name__)
    for i in range(0,100):
        func(*args, **kw)
    print("run 100 times ", end = '')


#slower
from PIL import ImageGrab
#@countTime
def getColor1(x, y):
    image = ImageGrab.grab()
    return image.getpixel((x, y))


#faster
from ctypes import *
#@countTime
def getColor2(x, y):
    gdi32 = windll.gdi32
    user32 = windll.user32
    hdc = user32.GetDC(None)  
    pixel = gdi32.GetPixel(hdc, x, y)  
    r = pixel & 0x0000ff
    g = (pixel & 0x00ff00) >> 8
    b = pixel >> 16
    return (r, g, b)


#yet another faster
import pyautogui
#@countTime
def getColor3(x, y):
    pix = pyautogui.pixel(100, 200)
    return (pix[0], pix[1], pix[2])


def check1():
    x, y = pyautogui.position()
    R, G, B = getColor3(x, y)
    if R <= 100 and G >= 130 and G <=190 and B >= 170 and B <= 220:
        pyautogui.click(x, y)


def check2():
    x, y = pyautogui.position()
    if pyautogui.pixelMatchesColor(x, y, (130, 135, 144), tolerance=30):
        pyautogui.click(x, y)


#trying multithread
import threading
class myThread (threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        testFunc(check1)

@countTime
def multiThread():
    thread1 = myThread()
    thread2 = myThread()
    thread3 = myThread()
    thread4 = myThread()
    thread1.start()
    time.sleep(0.01)
    thread2.start()
    time.sleep(0.01)
    thread3.start()
    time.sleep(0.01)
    thread4.start()
    time.sleep(0.01)
    thread1.join()
    thread2.join()
    thread3.join()
    thread4.join()



testFunc(getColor1, 114, 514)
testFunc(getColor2, 114, 514)
testFunc(getColor3, 114, 514)
testFunc(check1)
testFunc(check2)
testFunc(check1)
testFunc(check2)
testFunc(check1)
testFunc(check2)
multiThread()
Last modification:December 15th, 2019 at 01:15 am

Leave a Comment