¿Método más rápido de lectura de píxeles de pantalla en Python que PIL?

Actualmente estoy usando un lector de píxeles a través de AutoItv3 para realizar algunas acciones en un progtwig que ejecuta X directo; Un juego. En este momento el progtwig funciona bien, pero como ejercicio lo he estado reescribiendo en python. Ahora mismo puedo hacer:

import ImageGrab # Part of PIL image = ImageGrab.grab() #Define an area to capture. rgb = image.getpixel((1, 90)) #What pixel do we want? 

Y eso me permite obtener la información de píxeles que quiero, pero lo estoy haciendo bastante rápido (debe hacerse 3 veces por segundo o más rápido), pero el resultado es que afecta en gran medida a la velocidad de cuadros de este juego basado en DirectX.

¿Hay una forma más rápida en Python para leer un píxel de pantalla específico? Incluso limitar este a la ejecución cada 0,3 segundos está causando más tensión de la que realmente debería (en realidad pensé que python sería más rápido que AutoIt para este propósito en particular, de ahí la razón por la que lo bash)

Esta es la fuente de captura de pantalla del PIL, no acepta ningún parámetro y toma toda la pantalla y la convierte en bitmap.

 PyImaging_GrabScreenWin32(PyObject* self, PyObject* args) { int width, height; HBITMAP bitmap; BITMAPCOREHEADER core; HDC screen, screen_copy; PyObject* buffer; /* step 1: create a memory DC large enough to hold the entire screen */ screen = CreateDC(";DISPLAY", NULL, NULL, NULL); screen_copy = CreateCompatibleDC(screen); width = GetDeviceCaps(screen, HORZRES); height = GetDeviceCaps(screen, VERTRES); bitmap = CreateCompatibleBitmap(screen, width, height); if (!bitmap) goto error; if (!SelectObject(screen_copy, bitmap)) goto error; /* step 2: copy bits into memory DC bitmap */ if (!BitBlt(screen_copy, 0, 0, width, height, screen, 0, 0, SRCCOPY)) goto error; /* step 3: extract bits from bitmap */ buffer = PyString_FromStringAndSize(NULL, height * ((width*3 + 3) & -4)); if (!buffer) return NULL; core.bcSize = sizeof(core); core.bcWidth = width; core.bcHeight = height; core.bcPlanes = 1; core.bcBitCount = 24; if (!GetDIBits(screen_copy, bitmap, 0, height, PyString_AS_STRING(buffer), (BITMAPINFO*) &core, DIB_RGB_COLORS)) goto error; DeleteObject(bitmap); DeleteDC(screen_copy); DeleteDC(screen); return Py_BuildValue("(ii)N", width, height, buffer); error: PyErr_SetString(PyExc_IOError, "screen grab failed"); DeleteDC(screen_copy); DeleteDC(screen); return NULL; } 

Entonces, cuando acabo de profundizar un poco, el enfoque de C es bueno

http://msdn.microsoft.com/en-us/library/dd144909(VS.85).aspx

Y Python tiene ctypes, así que aquí está mi enfoque con ctypes (en Windows 10, winnt ha sido reemplazado por Windows ):

 >>> from ctypes import * >>> user= windll.LoadLibrary("c:\\winnt\\system32\\user32.dll") #I am in windows 2000, may be yours will be windows >>> h = user.GetDC(0) >>> gdi= windll.LoadLibrary("c:\\winnt\\system32\\gdi32.dll") >>> gdi.GetPixel(h,1023,767) 16777215 #I believe its white color of RGB or BGR value, #FFFFFF (according to msdn it should be RGB) >>> gdi.GetPixel(h,1024,767) -1 #because my screen is only 1024x768 

Podría escribir un contenedor para la función GetPixel como este

 from ctypes import windll dc= windll.user32.GetDC(0) def getpixel(x,y): return windll.gdi32.GetPixel(dc,x,y) 

Luego puedes usarlo como getpixel(0,0) , getpixel(100,0) , etc …

PD: El mío es Windows 2000, así que coloco winnt en la ruta, es posible que tengas que cambiarlo a windows o para eliminar la ruta por completo, solo user32.dll usar user32.dll y gdi32.dll debería funcionar.

Comente la solución de S.Mark: la biblioteca user32 ya está cargada por windll en windll.user32, así que en lugar de la línea dc = … puede hacer:

 def getpixel(x,y): return gdi.GetPixel(windll.user32.GetDC(0),x,y) 

… o preferiblemente:

 dc= windll.user32.GetDC(0) 

Es posible que pueda hacerlo a través de SDL (?). Basándose en esta pregunta , SDL puede acceder a la pantalla. Y tiene enlaces de python.

¿Podría valer la pena un tiro? Si funcionara, ciertamente sería más rápido que hacer una captura de pantalla completa en PIL.

Es una pregunta antigua, pero ocupa un lugar destacado en Google al buscar métodos de captura de pantalla de Python, por lo que creo que podría ser útil mencionar que el módulo ImageGrab ahora admite la captura de una región de la pantalla:

 PIL.ImageGrab.grab(bbox=None) Parameters: bbox – What region to copy. Default is the entire screen. Returns: An image 

http://pillow.readthedocs.io/en/3.1.x/reference/ImageGrab.html

Al ampliar ligeramente el scope, ahora también hay un reemplazo para ImageGrab llamado pyscreenshot, que también guarda parte de la pantalla en una imagen PIL / Pillow. Este módulo también funciona en Linux, a diferencia de ImageGrab que es solo para Windows y OS X.

 import pyscreenshot as ImageGrab im=ImageGrab.grab(bbox=(10,10,510,510)) # X1,Y1,X2,Y2 im.show() 

https://pypi.python.org/pypi/pyscreenshot