2010-01-04 9 views
8

वर्तमान में मैं सीधे X चला रहे प्रोग्राम में कुछ क्रियाएं करने के लिए ऑटोआईटीवी 3 के माध्यम से एक पिक्सेल रीडर का उपयोग कर रहा हूं; एक खेल। अभी कार्यक्रम ठीक काम करता है लेकिन एक अभ्यास के रूप में मैं इसे पायथन में फिर से लिख रहा हूं। अभी मैं कर सकते हैं:पीआईएल की तुलना में पाइथन में स्क्रीन पिक्सेल पढ़ने की तेज़ विधि?

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

और वह पिक्सेल जानकारी मैं अभी ठीक चाहते पकड़ लेता है, लेकिन मैं काफी तेजी से इस कर रहा हूँ (3x किया जाना एक दूसरे या तेज की जरूरत है), लेकिन परिणाम यह है कि है इस डायरेक्टएक्स-आधारित गेम के फ़्रेमेट को मुख्य रूप से प्रभावित करता है।

क्या पाइथन में एक विशिष्ट स्क्रीन पिक्सेल पढ़ने का कोई तेज तरीका है? यहां तक ​​कि हर 0.3 सेकंड चलाने के लिए यह एक सीमित अधिक तनाव उत्पन्न कर रहा है की तुलना में यह वास्तव में (मैं वास्तव में सोचा अजगर तेजी AutoIt की तुलना में इस विशेष उद्देश्य के लिए, हो सकता है इसलिए कारण मैं इसे कोशिश कर रहा हूँ) चाहिए

उत्तर

12

यह पीआईएल का grabscreen स्रोत है, यह किसी भी पैरामीटर को स्वीकार नहीं करता है, और यह पूरी स्क्रीन पकड़ लेता है और इसे बिटमैप में परिवर्तित करता है।

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

तो, जब मैं सिर्फ एक छोटे से गहरी जाओ, पाया सी दृष्टिकोण अच्छा

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

है और अजगर ctypes है, तो यहाँ 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 

उपयोग करते हुए मेरे दृष्टिकोण है आप फ़ंक्शन 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), आदि जैसे उपयोग कर सकते हैं ...

पुनश्च: मेरा Windows 2000 है, इसलिए मैं रास्ते में winnt शब्दों में कहें, आप windows करने के लिए इसे बदलने की जरूरत है सकते हैं या आप पूरी तरह से हटाने के chould पथ, बस user32.dll और gdi32.dll का उपयोग करना भी काम करना चाहिए। S.Mark के समाधान के

+0

धन्यवाद एक गुच्छा। यह स्क्रीन को नोटिसबैली पढ़ने के लिए प्रेरित किया गया। मैं जितनी तेजी से पढ़ सकता हूं उतना तेज़ी से पढ़ सकता हूं। ;) – ThantiK

+0

मैंने सीटीपीएस के लिए उपरोक्त वाक्यविन्यास की कोशिश की और लोड लोडर के साथ काम नहीं कर सका। रैपर फ़ंक्शन कोड ठीक वही है जो मैं ढूंढ रहा था। – Octipi

+0

मुझे विश्वास नहीं है कि यह वास्तव में दूसरे के लिए कम से कम 30 बार समय के साथ काम करता है। मैंने गेट पिक्सेल की कोशिश की है और इसमें समृद्ध समय लगेगा। –

3

आप हो सकता है एसडीएल (?) के माध्यम से ऐसा करने में सक्षम। this question के आधार पर, एसडीएल स्क्रीन तक पहुंच सकता है। और इसमें पाइथन बाइंडिंग है।

एक शॉट के लायक हो सकता है? अगर यह काम करता है तो यह निश्चित रूप से पीआईएल में पूर्ण स्क्रीन कैप्चर करने से तेज होगा।

7

टिप्पणी: user32 पुस्तकालय पहले से ही windll.user32 में windll से भरी हुई है, इसलिए डीसी के बजाय = ... लाइन आप कर सकते हैं:

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

...या अधिमानतः:

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

धन्यवाद, मैं आज सुबह 'cdll.user32.GetDC (0)' के साथ प्रयास कर रहा था, यह काम नहीं कर रहा था, इसलिए मैं मैन्युअल रूप से dll फ़ाइलों को आयात करता हूं। – YOU

1

यह एक पुराने सवाल है, लेकिन जब अजगर स्क्रीन हड़पने के तरीकों के लिए खोज यह गूगल पर काफी अत्यधिक स्थान पर है, तो मैं यह है कि ImageGrab मॉड्यूल अब के एक क्षेत्र हथियाने का समर्थन करता है उल्लेख करने के लिए उपयोगी हो सकता है लगता है स्क्रीन:

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

गुंजाइश थोड़ा विस्तार, वहाँ अब भी pyscreenshot बुलाया ImageGrab के लिए एक स्थानापन्न, वह भी एक या जनहित याचिका/तकिया छवि के लिए स्क्रीन के कुछ हिस्से बचाता है। यह मॉड्यूल लिनक्स पर भी काम करता है, इमेजग्राब के विपरीत जो केवल विंडोज और ओएस एक्स है।

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

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