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
How to Read Unknown Number of Inputs
Difference Between Function Overloading and Template Function Which Is More Appropriate
How to Print a Double Value With Full Precision Using Cout
What Are the Barriers to Understanding Pointers and What Can Be Done to Overcome Them
Running My C++ Code Gives Me a Blank Console
Difference Between 'Typedef' and 'Using' in C++11
What's the Most Efficient Way to Erase Duplicates and Sort a Vector
How to Print Current Time (With Milliseconds) Using C++/C++11
How to Detect Unsigned Integer Overflow
How to Initialize Private Static Members in C++
Difference Between G++ and Gcc
What Do Single Quotes Do in C++ When Used on Multiple Characters