在Python中阅读屏幕像素比PIL更快的方法?
目前我正在使用像素读取器通过AutoItv3在运行直接X的程序中执行某些操作;一个游戏。现在的程序运行良好,但作为一个练习,我一直在Python中重写它。现在我可以这样做:在Python中阅读屏幕像素比PIL更快的方法?
import ImageGrab # Part of PIL
image = ImageGrab.grab() #Define an area to capture.
rgb = image.getpixel((1, 90)) #What pixel do we want?
而且,抓住像素信息,我想就好了,但我相当迅速地这样做(需要做3倍第二或更快),但结果是,它主要影响这个基于DirectX的游戏的帧率。
Python中有更快的方式来读取特定的屏幕像素吗?即使限制这一个运行每0.3秒导致更多的应变比它真的应该(我实际上认为python将为比AutoIt更快为此特定目的,因此我试图它的原因)
这是PIL的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;
}
所以,当我刚去略深,测得C的做法是好的
http://msdn.microsoft.com/en-us/library/dd144909(VS.85).aspx
和Python有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)
,等...
PS:我的是Windows 2000的,所以我把winnt
的路径,则可能需要将其更改为windows
,或者你chould完全删除路径,只需使用user32.dll
和gdi32.dll
即可。在S.Mark的解决方案
评论:USER32库已经被加载由WINDLL到windll.user32,所以代替DC = ...行,你可以这样做:
def getpixel(x,y):
return gdi.GetPixel(windll.user32.GetDC(0),x,y)
...或较好的是:
dc= windll.user32.GetDC(0)
谢谢,我今天早上尝试用'cdll.user32.GetDC(0)',它没有工作,所以我手动导入dll文件。 – YOU 2010-01-04 11:14:58
这是一个老问题,但对于Python的屏幕抓取方法搜索时相当高排名在谷歌,所以我认为这可能是有用的一提的是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
略微扩大范围,现在也被称为ImageGrab一个pyscreenshot更换,这也保存到一个或PIL /枕头图像屏幕的某些部分。这个模块也适用于Linux,不像ImageGrab,它只是Windows和OS X。
import pyscreenshot as ImageGrab
im=ImageGrab.grab(bbox=(10,10,510,510)) # X1,Y1,X2,Y2
im.show()
感谢一大堆。这加快了屏幕阅读NOTICEABLY。我现在可以像现在想的那样快速阅读,而且几乎没有减速。 ;) – ThantiK 2010-01-13 22:14:52
我尝试了ctypes的上述语法,无法让它与LoadLibrary一起工作。包装函数代码正是我所期待的。 – Octipi 2013-07-30 09:08:46
我不能相信这个实际上至少在第二次的时间里有30次。我试过GetPixel,花了很多时间。 – 2016-01-19 08:26:26