使用X,y,getDibits和循环通过像素循环
题
我正在抓住屏幕的一部分,并通过像素扫描某个颜色范围。
我在看 MSDN捕获图像 示例并知道如何使用这些功能。
我可以将钻头放入数组中,但是我不确定如何以一种可以像图像一样循环的方式进行操作。伪示例(我敢肯定已经离开):
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];
}
}
这基本上就是我想做的,因此,如果红色,蓝色和绿色是某种颜色,我会知道图像中它在(x,y)的协调。
我只是不知道如何以这样的方式使用getDibit,以及如何适当地设置阵列以实现这一目标。
解决方案
除了已经给出的好答案外,这是一个例子 如何 要获得一个简单的阵列结构。 (您可以使用EG GOZ的代码 用于迭代。)
你必须选择 DIB_RGB_COLORS
作为标志 uUsage
并设置 BITMAPINFO
结构体 和 BITMAPINFOHEADER
结构体 它包含。当您设置时 biClrUsed
和 biClrImportant
为零,有“没有”颜色表,因此您可以阅读从中获得的位图的像素 GetDIBits
作为RGB值的序列。使用 32
作为位计数(biBitCount
)根据MSDN设置数据结构:
该位图最大为2^32颜色。如果是
biCompression
成员BITMAPINFOHEADER
是BI_RGB
, , 这bmiColors
成员BITMAPINFO
是NULL
. 。每个DWORD
在位图阵列中,对于像素,分别代表蓝色,绿色和红色的相对强度。每个中的高字节DWORD
未使用。
自MS以来 LONG
恰好是32位长(大小 DWORD
),您不必注意填充物(如 备注部分).
代码:
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
其他提示
GetDIBits
返回一维值数组。对于一个宽宽的位图宽且使用24位颜色的位图,第一行(m*3)字节将是第一行像素。可以随后进行一些填充字节。这取决于bitmapinfoheader。通常有填充物使宽度为4个字节的倍数。因此,如果您的位图宽33像素,则实际上将有(36*3)字节。
这个“像素加填充”称为“步幅”。对于RGB位图,您可以计算出: stride = (biWidth * (biBitCount / 8) + 3) & ~3
, , 在哪里 biWidth
和 biBitCount
取自Bitmapinfoheader。
我不确定您要如何穿越数组。如果您想从左上角到右上逐像素逐个像素(假设这是自上而下的位图):
for (row = 0; row < Image.Height; ++row)
{
int rowBase = row*stride;
for (col = 0; col < Image.Width; ++col)
{
red = lpPixels[rowBase + col];
// etc.
}
}
这并不容易。您的算法将取决于图像的颜色深度。如果是256或更少,您将没有像素颜色,而是柔软的颜色调色板。 16位像素可以是RGB555或RGB565,24位图像为RGB888,而32位图像将为RGBA或ARGB。您将需要Bitmapinfoheader来找出答案。
一旦发现,像素数据将只是一个大小宽度 *高度 *的数组 *(bitsperpixel / 8)
在您发布的链接中,您可以创建一个32位的位图,因此我假设您正在从32位位图中读取(此假设可能不正确)。
因此,将循环更改为以下内容应起作用:
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;
}
}
要牢记的事情:
1. arrays是基于C/C ++的0
2.您每次都在水平和垂直方向上踏上3个像素。这意味着您不会访问每个像素。
3.通常组织一个位图,使得有“宽度”像素的“高度”跨度。因此,您应该在跨越中跨过每个像素,然后移至下一个跨度。
4.正如已经指出的那样,请确保您正确阅读像素。在16位模式下它更复杂
MSDN的一些惊喜:
该表由一系列RGBQUAD数据结构组成。 (BitMapCoreInfo格式的表是使用RGBTriple数据结构构建的。)红色,绿色和蓝色字节 相反顺序 (红色交换位置与蓝色)来自Windows约定。
因此,getDibits()之后的内存中的颜色在内存中以BGR顺序为单位。