Более быстрый метод чтения экранного пикселя в Python, чем PIL?

В настоящее время я использую пиксельного читателя через AutoItv3 для выполнения некоторых действий в программе, которая работает прямой X; игра. Прямо сейчас программа хорошо работает, но как осуществление я переписывал ее в Python. Прямо сейчас я могу сделать:

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

И это захватывает информацию о пикселе, которую я хочу очень хорошо, но я делаю, это вполне быстро (должен быть сделан 3x секунда или быстрее), но результат состоит в том, что она абсолютно влияет на framerate этой основанной на DirectX игры.

Существует ли более быстрый путь в Python для чтения определенного экранного пикселя? Даже ограничивая этот выполнением каждые 0.3 секунды вызывает больше деформации, чем это действительно должно (я на самом деле полагал, что Python будет быстрее, чем AutoIt для этой конкретной цели, следовательно причина, я пробую его),

9
задан ThantiK 4 January 2010 в 05:41
поделиться

3 ответа

[

] Это источник грейферного экрана ПИЛа, он не принимает никаких параметров, и он захватывает весь экран и преобразует его в растровое изображение.[

] [
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;
}
] [

] Итак, когда я немного углубляюсь, то обнаруживаю, что подход C хорош [

]. [

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

] [

] А у Python есть стипы, так что вот мой подход с использованием стипов (в Windows 10, [] winnt[] заменен на [] 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
] [

] Можно написать такую обертку для функции GetPixel[

]. [
from ctypes import windll
dc= windll.user32.GetDC(0)

def getpixel(x,y):
    return windll.gdi32.GetPixel(dc,x,y)
] [

] Тогда вы можете использовать как []getpixel(0,0)[], []getpixel(100,0)[] и т.д...[

]. [

][]PS: Мой - Windows 2000, поэтому я вставил []winnt[] в путь, вам может понадобиться изменить его на []windows[] или вы должны полностью удалить путь, просто используя []user32.dll[] и []gdi32.dll[] тоже должно сработать.[][

].
17
ответ дан 4 December 2019 в 07:35
поделиться

Комментарий к решению С.Марка: библиотека user32 уже загружена winll в windll.user32, так что вместо dc = ... строки можно сделать:

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

... или предпочтительнее:

dc= windll.user32.GetDC(0)
7
ответ дан 4 December 2019 в 07:35
поделиться

Вы можете сделать это через SDL (?). Основываясь на этом вопросе , SDL может получить доступ к экрану. И у него есть питоновые крепления.

Может, стоит попробовать? Если бы он работал, это было бы быстрее, чем делать полноэкранный снимок в PIL.

3
ответ дан 4 December 2019 в 07:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: