GetDIBits and pass-through pixels using X, Y

I grab a portion of the screen and look at the pixels for a specific range of colors.

I reviewed the MSDN Capture the Image example and know how to use the functions.

I can get the bits into an array, but I'm not sure how to do it so that I can scroll it as I would like. Pseudo-example (which I am sure left):

for ( x = 1; x <= Image.Width; x += 3 ) { for ( y = 1; y <= Image.Height; y += 3 ) { red = lpPixels[x]; green = lpPixels[x + 1]; blue = lpPixels[x + 2]; } } 

This is basically what I want to do, so if the red, blue and green colors are a specific color, I will know what coordinate it has (x, y) in the image.

I just don’t know how to use GetDIBits in this way and how to configure the array accordingly to accomplish this.

+7
c ++ loops pixels
source share
5 answers

Besides the good answers already given here, an example of how to get a simple array structure to go further. (You can use, for example, Goz code for iteration.)

GetDIBits @MSDN link

You must select DIB_RGB_COLORS as the flag for uUsage and configure the BITMAPINFO structure and the BITMAPINFOHEADER structure that contains. When you set biClrUsed and biClrImportant to zero, there is a no color table, so you can read the pixels of the bitmap that you get from GetDIBits as a sequence of RGB values. Using 32 as the number of bits ( biBitCount ) sets the data structure according to MSDN:

A bitmap has a maximum of 2 ^ 32 colors. If the biCompression BITMAPINFOHEADER is BI_RGB , the member of bmiColors BITMAPINFO is NULL . Each DWORD in an array of raster images represents the relative intensities of blue, green, and red, respectively, for a pixel. High byte in each DWORD not used.

Since MS LONG has exactly 32 bits (size a DWORD ), you do not need to pay attention to filling (as described in the Notes section ).

the code:

 HDC hdcSource = NULL; // the source device context HBITMAP hSource = NULL; // the bitmap selected into the device context BITMAPINFO MyBMInfo = {0}; MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader); // Get the BITMAPINFO structure from the bitmap if(0 == GetDIBits(hdcSource, hSource, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) { // error handling } // create the pixel buffer BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage]; // We'll change the received BITMAPINFOHEADER to request the data in a // 32 bit RGB format (and not upside-down) so that we can iterate over // the pixels easily. // requesting a 32 bit image means that no stride/padding will be necessary, // although it always contains an (possibly unused) alpha channel MyBMInfo.bmiHeader.biBitCount = 32; MyBMInfo.bmiHeader.biCompression = BI_RGB; // no compression -> easier to use // correct the bottom-up ordering of lines (abs is in cstdblib and stdlib.h) MyBMInfo.bmiHeader.biHeight = abs(MyBMInfo.bmiHeader.biHeight); // Call GetDIBits a second time, this time to (format and) store the actual // bitmap data (the "pixels") in the buffer lpPixels if(0 == GetDIBits(hdcSource, hSource, 0, MyBMInfo.bmiHeader.biHeight, lpPixels, &MyBMInfo, DIB_RGB_COLORS)) { // error handling } // clean up: deselect bitmap from device context, close handles, delete buffer 
+11
source share

GetDIBits returns a one-dimensional array of values. For a bitmap that is M pixels wide by N pixels high and uses 24-bit color, the first (M * 3) bytes will be the first row of pixels. This may be followed by some padding bytes. It depends on the BITMAPINFOHEADER. Usually, padding is typically used to fill in a width of 4 bytes. Therefore, if your bitmap is 33 pixels wide, there will actually be (36 * 3) bytes per line.

This "pixel plus additive" is called the "step". For RGB bitmaps, you can calculate the step using: stride = (biWidth * (biBitCount / 8) + 3) & ~3 , where biWidth and biBitCount are taken from BITMAPINFOHEADER.

I'm not sure how you want to traverse the array. If you want to go in half in the upper left corner to the right (provided that this bitmap is from top to bottom):

 for (row = 0; row < Image.Height; ++row) { int rowBase = row*stride; for (col = 0; col < Image.Width; ++col) { red = lpPixels[rowBase + col]; // etc. } } 
+9
source share

It is not so easy. Your algorithm will depend on the color depth of the image. If it's 256 or less, you won't have pixel colors, but it will look in the color picker. 16-bit pixels can be RGB555 or RGB565, 24-bit images will be RGB888, and 32-bit images will be RGBA or ARGB. You will need BITMAPINFOHEADER to find out.

Once you find out, the pixel data will just be an array of width * height * (BitsPerPixel / 8)

+2
source share

In the post you post, you create a 32-bit bitmap, so I assume that you are reading from a 32-bit bitmap (this assumption may be wrong).

Therefore, you need to change your loop to the following:

 char* pCurrPixel = (char*)lpPixels; for ( y = 0; y < Image.Height; y++ ) { for ( x = 0; x < Image.Width; x++ ) { red = pCurrPixel[0]; green = pCurrPixel[1]; blue = pCurrPixel[2]; pCurrPixel += 4; } } 

What you need to remember:

1.Archives are based on 0 in C / C ++
2. Each time you typed 3 pixels horizontally and vertically. This meant that you were not visiting every pixel.
3. A bitmap image is usually organized in such a way that there are "heights" of intervals of "widths" of pixels. Therefore, you need to go through each pixel in the gap, and then move on to the next range.
4. As already mentioned, make sure you read the pixels correctly. in 16-bit mode its more complex

+2
source share

Some surprise from MSDN:

The table consists of an array of RGBQUAD data structures. (The table for the BITMAPCOREINFO format is built with the RGBTRIPLE data structure.) Red, green, and blue bytes in the reverse order (red swaps position with blue) from the Windows convention.

therefore the colors are in BGR order in memory after GetDIBits ()

0
source share

All Articles