How to Read the Screen Pixels

How to read the screen pixels?

Starting with your code and omitting error checking ...

// Create a BITMAPINFO specifying the format you want the pixels in.
// To keep this simple, we'll use 32-bits per pixel (the high byte isn't
// used).
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = nScreenWidth;
bmi.bmiHeader.biHeight = nScreenHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;

// Allocate a buffer to receive the pixel data.
RGBQUAD *pPixels = new RGBQUAD[nScreenWidth * nScreenHeight];

// Call GetDIBits to copy the bits from the device dependent bitmap
// into the buffer allocated above, using the pixel format you
// chose in the BITMAPINFO.
::GetDIBits(hCaptureDC,
hCaptureBitmap,
0, // starting scanline
nScreenHeight, // scanlines to copy
pPixels, // buffer for your copy of the pixels
&bmi, // format you want the data in
DIB_RGB_COLORS); // actual pixels, not palette references

// You can now access the raw pixel data in pPixels. Note that they are
// stored from the bottom scanline to the top, so pPixels[0] is the lower
// left pixel, pPixels[1] is the next pixel to the right,
// pPixels[nScreenWidth] is the first pixel on the second row from the
// bottom, etc.

// Don't forget to free the pixel buffer.
delete [] pPixels;

glReadPixels with screen pixels

As mentioned in the other answer and comments You can use glReadPixels only for pixels inside your OpenGL context window that are actually rendered at that time ... As you mentioned you have used GetPixel it hints you are using GDI. In that case you are trying to read GDI Canvas pixel from OpenGL which is not possible (the other way around is possible however but slow). So I advice to read this:

  • How can I access a graphics card's output directly?

Where you can find example of both methods. If you are trying to obtain pixel from your own app then you can use different api then GetPixel.

If you're in VCL environment use Graphics::TBitmap::ScanLine property which can be used for direct pixel access without restrictions or performance hits if used properly.

On MSVC++ of GCC environment use WinAPI BitBlt but that is a bit slower and not as elegant (at least from my point of view).

Getting pixel information from the screen quickly [duplicate]

Try using createScreenCapture(Rectangle screenRect) of Robot class to get the BufferedImage and then use getRGB(int x, int y) of BufferedImage. That should be fast

Faster method of reading screen pixel in Python than PIL?

This is the PIL's grabscreen source, Its does not accept any parameters, and Its grab the whole screen and convert it to 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;
}

So, when I just go a little deep, found C approach is good

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

And Python has ctypes, so here is my approach using ctypes (in Windows 10, winnt has been replaced with 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

You could write a wrapper for function GetPixel like this

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

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

Then you can use like getpixel(0,0), getpixel(100,0), etc...

PS: Mine is Windows 2000, so I put winnt in the path, you may need to change it to windows or you chould completely remove path, just using user32.dll and gdi32.dll should work too.



Related Topics



Leave a reply



Submit