views:

99

answers:

4

I'm grabbing a portion of the screen and scanning through the pixels for a certain color range.

I looked at MSDN's Capturing an 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 in such a way that I can loop through it as I would an image. A pseudo-example (which I'm sure is way off):

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

That's basically what I want to do, so if red, blue, and green is a certain color, I'll know what coordinate it's at (x, y) in the image.

I just don't know how to use GetDIBits in such a way, and how to setup the array appropriately to be able to accomplish this.

+1  A: 

It's not so easy. Your algorithm will depend on the colour depth of the image. If it's 256 or less you won't have pixel colours, but indeces into a palette of colours. 16-bit pixels could be RGB555 or RGB565, 24-bit images will be RGB888, and 32-bit images will be RGBA or ARGB. You'll need the BITMAPINFOHEADER to find out.

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

James
+1. Alternatively you can try copy/blit to a bitmap with fixed/known color depth.
jdv
I think the OP selects the bitmap into the DeviceContext, so has full control on the bitmap. Using 24 bit and no compression allow to read it as RGB888 easily.
DyP
A: 

GetDIBits returns a one-dimensional array of values. For a bitmap that's M pixels wide by N pixels tall and uses 24-bit color, the first (M*3) bytes will be the first row of pixels. That can be followed by some padding bytes. It depends on the BITMAPINFOHEADER. There is usually padding to make the width a multiple of 4 bytes. So if your bitmap is 33 pixels wide, there will actually be (36*3) bytes per row.

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

I'm not sure how you want to traverse the array. If you want to go pixel-by-pixel from top left to lower right (assuming this is a top-down bitmap):

for (row = 0; row < Image.Height; ++row)
{
    int rowBase = row*stride;
    for (col = 0; col < Image.Width; ++col)
    {
        red = lpPixels[rowBase + col];
        // etc.
    }
}
Jim Mischel
DyP
+1  A: 

In the link you post you create a 32-bit bitmap so I'll assume you are reading from a 32-bit bitmap (This assumption may be incorrect).

Therefore changing your loop to the following should work:

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

Things to bear in mind:

1.Arrays are 0 based in C/C++
2. You were stepping 3 pixels horizontally and vertically each time. Which meant you aren't visiting every pixel.
3. A bitmap is usually organised such that there are "height" spans of "width" pixels. Therefore you should step through each pixel in a span and then move to the next span.
4. As already pointed out make sure you aare reading pixels correctly. in 16-bit mode its more complex

Goz
+1  A: 
DyP