我正在抓住屏幕的一部分,并通过像素扫描某个颜色范围。

我在看 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的代码 用于迭代。)

getDibits参考 @ msdn

你必须选择 DIB_RGB_COLORS 作为标志 uUsage 并设置 BITMAPINFO 结构体BITMAPINFOHEADER 结构体 它包含。当您设置时 biClrUsedbiClrImportant 为零,有“没有”颜色表,因此您可以阅读从中获得的位图的像素 GetDIBits 作为RGB值的序列。使用 32 作为位计数(biBitCount)根据MSDN设置数据结构:

该位图最大为2^32颜色。如果是 biCompression 成员 BITMAPINFOHEADERBI_RGB, , 这 bmiColors 成员 BITMAPINFONULL. 。每个 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, , 在哪里 biWidthbiBitCount 取自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顺序为单位。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top