如何在 Python 中快速找到屏幕上的内容?
How can I locate something on my screen quickly in Python?
我试过使用 pyautogui 模块和我在屏幕上定位图像的功能
pyautogui.locateOnScreen()
但它的处理时间约为 5-10 秒。有没有其他方法可以让我更快地在屏幕上定位图像?基本上,我想要一个更快的 locateOnScreen() 版本。
如果您正在寻找图像识别,您可以使用 Sikuli. Check the Hello World tutorial。
official documentation 说在 1920x1080 的屏幕上应该需要 1-2 秒,所以你的时间似乎有点慢。我会尝试优化:
- 除非颜色信息很重要,否则使用灰度(
grayscale=True
应该提供 30% 左右的加速)
- 使用较小的图像来定位(如果这已经唯一标识了您需要获得的位置,则只选择一部分)
- 不要每次都从文件中加载需要定位的图像,而是将其保存在内存中
- 如果您已经了解可能的位置(例如,从以前的运行中),请传入区域参数
以上链接的文档中均有描述。
这仍然不够快吗,您可以检查 sources of pyautogui,看到屏幕上的定位使用了 Python 中实现的特定算法(Knuth-Morris-Pratt 搜索算法)。因此,在 C 中实现这部分可能会导致相当明显的加速。
制作一个函数并使用线程信心(需要opencv)
import pyautogui
import threading
def locate_cat():
cat=None
while cat is None:
cat = pyautogui.locateOnScreen('Pictures/cat.png',confidence=.65,region=(1722,748, 200,450)
return cat
如果您知道它在屏幕上的大致位置,则可以使用区域参数
在某些情况下,您可以在屏幕上定位并将该区域分配给一个变量,并使用 region=somevar 作为参数,以便它看起来与上次找到它的位置相同,以帮助加快检测过程.
例如:
import pyautogui
def first_find():
front_door = None
while front_door is None:
front_door_save=pyautogui.locateOnScreen('frontdoor.png',confidence=.95,region=1722,748, 200,450)
front_door=front_door_save
return front_door_save
def second_find():
front_door=None
while front_door is None:
front_door = pyautogui.locateOnScreen('frontdoor.png',confidence=.95,region=front_door_save)
return front_door
def find_person():
person=None
while person is None:
person= pyautogui.locateOnScreen('person.png',confidence=.95,region=front_door)
while True:
first_find()
second_find()
if front_door is None:
pass
if front_door is not None:
find_person()
我遇到了与 pyautogui 相同的问题。虽然它是一个非常方便的库,但速度很慢。
我依靠 cv2 和 PIL 获得了 10 倍的加速:
def benchmark_opencv_pil(method):
img = ImageGrab.grab(bbox=REGION)
img_cv = cv.cvtColor(np.array(img), cv.COLOR_RGB2BGR)
res = cv.matchTemplate(img_cv, GAME_OVER_PICTURE_CV, method)
# print(res)
return (res >= 0.8).any()
使用 TM_CCOEFF_NORMED 效果很好。 (当然你也可以调整0.8的阈值)
来源:Fast locateOnScreen with Python
为了完整起见,这里是完整的基准测试:
import pyautogui as pg
import numpy as np
import cv2 as cv
from PIL import ImageGrab, Image
import time
REGION = (0, 0, 400, 400)
GAME_OVER_PICTURE_PIL = Image.open("./balloon_fight_game_over.png")
GAME_OVER_PICTURE_CV = cv.imread('./balloon_fight_game_over.png')
def timing(f):
def wrap(*args, **kwargs):
time1 = time.time()
ret = f(*args, **kwargs)
time2 = time.time()
print('{:s} function took {:.3f} ms'.format(
f.__name__, (time2-time1)*1000.0))
return ret
return wrap
@timing
def benchmark_pyautogui():
res = pg.locateOnScreen(GAME_OVER_PICTURE_PIL,
grayscale=True, # should provied a speed up
confidence=0.8,
region=REGION)
return res is not None
@timing
def benchmark_opencv_pil(method):
img = ImageGrab.grab(bbox=REGION)
img_cv = cv.cvtColor(np.array(img), cv.COLOR_RGB2BGR)
res = cv.matchTemplate(img_cv, GAME_OVER_PICTURE_CV, method)
# print(res)
return (res >= 0.8).any()
if __name__ == "__main__":
im_pyautogui = benchmark_pyautogui()
print(im_pyautogui)
methods = ['cv.TM_CCOEFF', 'cv.TM_CCOEFF_NORMED', 'cv.TM_CCORR',
'cv.TM_CCORR_NORMED', 'cv.TM_SQDIFF', 'cv.TM_SQDIFF_NORMED']
# cv.TM_CCOEFF_NORMED actually seems to be the most relevant method
for method in methods:
print(method)
im_opencv = benchmark_opencv_pil(eval(method))
print(im_opencv)
结果显示提高了 10 倍。
benchmark_pyautogui function took 175.712 ms
False
cv.TM_CCOEFF
benchmark_opencv_pil function took 21.283 ms
True
cv.TM_CCOEFF_NORMED
benchmark_opencv_pil function took 23.377 ms
False
cv.TM_CCORR
benchmark_opencv_pil function took 20.465 ms
True
cv.TM_CCORR_NORMED
benchmark_opencv_pil function took 25.347 ms
False
cv.TM_SQDIFF
benchmark_opencv_pil function took 23.799 ms
True
cv.TM_SQDIFF_NORMED
benchmark_opencv_pil function took 22.882 ms
True
我试过使用 pyautogui 模块和我在屏幕上定位图像的功能
pyautogui.locateOnScreen()
但它的处理时间约为 5-10 秒。有没有其他方法可以让我更快地在屏幕上定位图像?基本上,我想要一个更快的 locateOnScreen() 版本。
如果您正在寻找图像识别,您可以使用 Sikuli. Check the Hello World tutorial。
official documentation 说在 1920x1080 的屏幕上应该需要 1-2 秒,所以你的时间似乎有点慢。我会尝试优化:
- 除非颜色信息很重要,否则使用灰度(
grayscale=True
应该提供 30% 左右的加速) - 使用较小的图像来定位(如果这已经唯一标识了您需要获得的位置,则只选择一部分)
- 不要每次都从文件中加载需要定位的图像,而是将其保存在内存中
- 如果您已经了解可能的位置(例如,从以前的运行中),请传入区域参数
以上链接的文档中均有描述。
这仍然不够快吗,您可以检查 sources of pyautogui,看到屏幕上的定位使用了 Python 中实现的特定算法(Knuth-Morris-Pratt 搜索算法)。因此,在 C 中实现这部分可能会导致相当明显的加速。
制作一个函数并使用线程信心(需要opencv)
import pyautogui
import threading
def locate_cat():
cat=None
while cat is None:
cat = pyautogui.locateOnScreen('Pictures/cat.png',confidence=.65,region=(1722,748, 200,450)
return cat
如果您知道它在屏幕上的大致位置,则可以使用区域参数
在某些情况下,您可以在屏幕上定位并将该区域分配给一个变量,并使用 region=somevar 作为参数,以便它看起来与上次找到它的位置相同,以帮助加快检测过程.
例如:
import pyautogui
def first_find():
front_door = None
while front_door is None:
front_door_save=pyautogui.locateOnScreen('frontdoor.png',confidence=.95,region=1722,748, 200,450)
front_door=front_door_save
return front_door_save
def second_find():
front_door=None
while front_door is None:
front_door = pyautogui.locateOnScreen('frontdoor.png',confidence=.95,region=front_door_save)
return front_door
def find_person():
person=None
while person is None:
person= pyautogui.locateOnScreen('person.png',confidence=.95,region=front_door)
while True:
first_find()
second_find()
if front_door is None:
pass
if front_door is not None:
find_person()
我遇到了与 pyautogui 相同的问题。虽然它是一个非常方便的库,但速度很慢。
我依靠 cv2 和 PIL 获得了 10 倍的加速:
def benchmark_opencv_pil(method):
img = ImageGrab.grab(bbox=REGION)
img_cv = cv.cvtColor(np.array(img), cv.COLOR_RGB2BGR)
res = cv.matchTemplate(img_cv, GAME_OVER_PICTURE_CV, method)
# print(res)
return (res >= 0.8).any()
使用 TM_CCOEFF_NORMED 效果很好。 (当然你也可以调整0.8的阈值)
来源:Fast locateOnScreen with Python
为了完整起见,这里是完整的基准测试:
import pyautogui as pg
import numpy as np
import cv2 as cv
from PIL import ImageGrab, Image
import time
REGION = (0, 0, 400, 400)
GAME_OVER_PICTURE_PIL = Image.open("./balloon_fight_game_over.png")
GAME_OVER_PICTURE_CV = cv.imread('./balloon_fight_game_over.png')
def timing(f):
def wrap(*args, **kwargs):
time1 = time.time()
ret = f(*args, **kwargs)
time2 = time.time()
print('{:s} function took {:.3f} ms'.format(
f.__name__, (time2-time1)*1000.0))
return ret
return wrap
@timing
def benchmark_pyautogui():
res = pg.locateOnScreen(GAME_OVER_PICTURE_PIL,
grayscale=True, # should provied a speed up
confidence=0.8,
region=REGION)
return res is not None
@timing
def benchmark_opencv_pil(method):
img = ImageGrab.grab(bbox=REGION)
img_cv = cv.cvtColor(np.array(img), cv.COLOR_RGB2BGR)
res = cv.matchTemplate(img_cv, GAME_OVER_PICTURE_CV, method)
# print(res)
return (res >= 0.8).any()
if __name__ == "__main__":
im_pyautogui = benchmark_pyautogui()
print(im_pyautogui)
methods = ['cv.TM_CCOEFF', 'cv.TM_CCOEFF_NORMED', 'cv.TM_CCORR',
'cv.TM_CCORR_NORMED', 'cv.TM_SQDIFF', 'cv.TM_SQDIFF_NORMED']
# cv.TM_CCOEFF_NORMED actually seems to be the most relevant method
for method in methods:
print(method)
im_opencv = benchmark_opencv_pil(eval(method))
print(im_opencv)
结果显示提高了 10 倍。
benchmark_pyautogui function took 175.712 ms
False
cv.TM_CCOEFF
benchmark_opencv_pil function took 21.283 ms
True
cv.TM_CCOEFF_NORMED
benchmark_opencv_pil function took 23.377 ms
False
cv.TM_CCORR
benchmark_opencv_pil function took 20.465 ms
True
cv.TM_CCORR_NORMED
benchmark_opencv_pil function took 25.347 ms
False
cv.TM_SQDIFF
benchmark_opencv_pil function took 23.799 ms
True
cv.TM_SQDIFF_NORMED
benchmark_opencv_pil function took 22.882 ms
True