Первый раз задаем вопрос о SO.
Я пытаюсь найти быстрый способ чтения экрана в реальном времени (60fps+). Скриншот для numpy - быстрый метод, но не соответствует этой скорости. В этом вопросе есть блестящий ответ для пикселей: Самый эффективный/быстрый способ анализа данных с помощью Python?
Я попытался изменить GetPixel на эту длинную форму для BMP, но это уменьшает ее до 5 кадров в секунду:
t1 = time.time()
count = 0
width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
left = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)
top = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)
while count < 1000:
hwin = win32gui.GetDesktopWindow()
hwindc = win32gui.GetWindowDC(hwin)
srcdc = win32ui.CreateDCFromHandle(hwindc)
memdc = srcdc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(srcdc, width, height)
memdc.SelectObject(bmp)
memdc.BitBlt((0, 0), (width, height), srcdc, (left, top), win32con.SRCCOPY)
bmpinfo = bmp.GetInfo()
bmpInt = bmp.GetBitmapBits(False)
count +=1
t2 = time.time()
tf = t2-t1
it_per_sec = int(count/tf)
print (str(it_per_sec) + " iterations per second")
Я смотрел видео с youtube парня, работающего на С#, где он сказал, что GetPixel открывает и закрывает память, и поэтому использование GetPixel для каждого отдельного пикселя имеет много накладных расходов. Он предложил заблокировать все поле данных и только затем сделать getpixel. Я не знаю, как это сделать, поэтому любая помощь будет оценена по достоинству. (EDIT: эта ссылка может ссылаться на Небезопасную обработку изображений на Python, например LockBits в С#)
Существует также другой метод, который получает адрес памяти растрового изображения, но я не знаю, что с ним делать. Логика заключается в том, что я должен иметь возможность считывать память из этой точки в любой массив numpy, но я не смог этого сделать.
Также будет оценена любая другая возможность быстро прочитать экран.
Должен быть какой-то способ, GPU знает, какие пиксели рисовать в каждом месте, это означает, что в нем должен быть какой-то банк памяти или поток данных, к которому мы можем подключиться.
PS почему требуется высокая скорость? Я работаю над инструментами автоматизации работы, у которых много накладных расходов, и я надеюсь оптимизировать поток данных экрана, чтобы помочь этой части проекта.
В приведенном ниже коде используется MSS, который, если он изменен, чтобы показать отсутствие выхода, может достигать 44fps для 1080p. https://python-mss.readthedocs.io/examples.html#opencv-numpy
import time
import cv2
import mss
import numpy
with mss.mss() as sct:
# Part of the screen to capture
monitor = {'top': 40, 'left': 0, 'width': 800, 'height': 640}
while 'Screen capturing':
last_time = time.time()
# Get raw pixels from the screen, save it to a Numpy array
img = numpy.array(sct.grab(monitor))
# Display the picture
#cv2.imshow('OpenCV/Numpy normal', img)
# Display the picture in grayscale
# cv2.imshow('OpenCV/Numpy grayscale',
# cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY))
print('fps: {0}'.format(1 / (time.time()-last_time)))
# Press "q" to quit
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
Все еще не идеально, хотя, как это не 60fps+, и использование необработанного переупакованного буфера с графического процессора было бы лучшим решением, если это было возможно.