2010-01-04 16 views
8

Şu anda doğrudan X çalıştıran bir programda bazı eylemleri gerçekleştirmek için AutoItv3 aracılığıyla bir piksel okuyucu kullanıyorum; Bir oyun. Şu anda program iyi çalışıyor ama bir egzersiz olarak python'da yeniden yazdım. Şu anda yapabileceğim:Python'da PIL'den daha hızlı okuma pixel yöntemi mi?

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

Ve ben sadece iyi istediğiniz piksel bilgi yakalar, ama oldukça hızlı yapıyorum (ikinci veya daha hızlı 3x yapılması gerektiğini), ancak sonuç öyle mi DirectX tabanlı oyunun karesini büyük ölçüde etkiler.

Python'da belirli bir ekran pikselini okumak için daha hızlı bir yol var mı? Hatta gerçekten

cevap

12

Bu, PIL'in grabscreen kaynağıdır. Herhangi bir parametreyi kabul etmez ve tüm ekranı kapar ve bitmap'e dönüştürür.

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

Yani, biraz derin gittiğinizde, bulunan C yaklaşım

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

iyidir Ve Python ctypes var, Yani burada ctypes

>>> 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 

kullanarak yaklaşımdır GetPixel bu gibi bir sarmalayıcı yazabilirsin

Mine Windows 2000, bu yüzden yolda winnt koymak, sen windows olarak değiştirmek gerekebilir veya tamamen kaldırmak chould:

Sonra ... getpixel(0,0), getpixel(100,0) vb gibi

PS kullanabilirsiniz Sadece user32.dll ve gdi32.dll kullanarak yol çalışması gerekir. S.Mark çözümüne bağlı

+0

Çok teşekkürler. Bu ekran yukarı NOTLARABLY okuyor. Hemen hemen hiç yavaşlama olmadan istediğim kadar hızlı okuyabilirim. ;) – ThantiK

+0

Yukarıdaki sözdizimini denemeler için denedim ve LoadLibrary ile çalışamıyorum. Sarıcı işlev kodu tam olarak aradığım şey. – Octipi

+0

Bunun gerçekten de zamanla en az 30 kez çalıştığına inanamıyorum. GetPixel'i denedim ve en fazla zaman harcadı. –

3

Olabilirsin (aslında anladım piton, bunu deniyorum dolayısıyla nedeni bu özel amaç için AutoIt dahahızlı olacaktır) gerekenden daha fazla gerginlik neden olan her 0.3 saniyede bir fotoğraf için bu bir sınırlama SDL (?) ile yapabilecekler. this question dayanarak, SDL ekrana erişebilir. Ve python bağlamaları vardır.

Bir atışa değer mi? Eğer işe yaradıysa, PIL'de tam ekran çekimi yapmaktan kesinlikle daha hızlı olacaktır.

7

Yorum: user32 kütüphane zaten windll.user32 içine WinDll yazın tarafından yüklenmiştir, dolayısıyla yerine dc = ... çizgi Yapabileceğiniz:

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

...ya da tercihen:

dc= windll.user32.GetDC(0) 
+0

Teşekkürler, bu sabah 'cdll.user32.GetDC (0)' ile çalışıyordum, işe yaramadı, bu yüzden dll dosyalarını el ile içe aktarıyorum. – YOU

1

Bu eski bir soru, fakat Python ekran kapmak yöntemlerine ararken Google'da oldukça yüksek bir mertebeye, yüzden ImageGrab modülü artık bir bölgesini kapma destekler belirtmeyi yararlı olabilir düşünüyorum ekran: hafif kapsamının genişletilmesi

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

da artık aynı zamanda bir ya da PIL/Yastık görüntüye ekranın bir kısmını kaydeder pyscreenshot denilen ImageGrab yerini vardır. Bu modül, sadece Windows ve OS X olan ImageGrab'ın aksine Linux üzerinde de çalışır.

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

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