C++ Getting RGB from hBitmap

C++ Getting RGB from hBitmap

本文关键字:hBitmap from RGB Getting C++      更新时间:2023-10-16

使用位图对我来说是非常新的,所以我一直在努力学习我读过的在线教程和策略。基本上,我的目标是扫描屏幕以寻找特定的RGB值。我相信这样做的步骤是在hBitmap中捕获屏幕,然后从中产生一个RGB值数组,我可以扫描它。

我最初开始与GetPixel,但这是非常缓慢的。解决方案是使用GetDIBits,它生成RGB值数组。问题是,它返回奇怪的,可能是随机的RGB值。

我使用以下代码,这是我从另一个教程中找到的:

/* Globals */
int ScreenX = GetDeviceCaps(GetDC(0), HORZRES);
int ScreenY = GetDeviceCaps(GetDC(0), VERTRES);
BYTE* ScreenData = new BYTE[3*ScreenX*ScreenY];
void ScreenCap() {
    HDC hdc = GetDC(GetDesktopWindow());
    HDC hdcMem = CreateCompatibleDC (hdc);
    HBITMAP hBitmap = CreateCompatibleBitmap(hdc, ScreenX, ScreenY);
    BITMAPINFOHEADER bmi = {0};
    bmi.biSize = sizeof(BITMAPINFOHEADER);
    bmi.biPlanes = 1;
    bmi.biBitCount = 24;
    bmi.biWidth = ScreenX;
    bmi.biHeight = -ScreenY;
    bmi.biCompression = BI_RGB;
    bmi.biSizeImage = ScreenX * ScreenY;
    SelectObject(hdcMem, hBitmap);
    BitBlt(hdcMem, 0, 0, ScreenX, ScreenY, hdc, 0, 0, SRCCOPY);
    GetDIBits(hdc, hBitmap, 0, ScreenY, ScreenData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
    DeleteDC(hdcMem);
    ReleaseDC(NULL, hdc);
}
inline int PosR(int x, int y) {
    return ScreenData[3*((y*ScreenX)+x)+2];
}
inline int PosG(int x, int y) {
    return ScreenData[3*((y*ScreenX)+x)+1];
}
inline int PosB(int x, int y) {
    return ScreenData[3*((y*ScreenX)+x)];
}

我用下面的代码进行测试。我按Shift键调用ScreenCap,然后我将光标移动到所需位置,并按空格键查看该位置的RGB值。我是不是完全疯了?

int main() {
while ( true ) {
   if (GetAsyncKeyState(VK_SPACE)){  
      // Print out current cursor position
      GetCursorPos(&p);
      printf("X:%d Y:%d n",p.x,p.y);
      // Print out RGB value at that position
      int r = PosR(p.x, p.y);
      int g = PosG(p.x, p.y);
      int b = PosB(p.x, p.y);
      printf("r:%d g:%d b:%d n",r,g,b);
   } else if (GetAsyncKeyState(VK_ESCAPE)){
      printf("Quitn");
      break;
   } else if (GetAsyncKeyState(VK_SHIFT)){
      ScreenCap();
      printf("Capturedn");
   }
}
system("PAUSE");
return 0;
}

问题是你的屏幕实际上是32位深而不是24位。下面的代码将为您提供所需的结果:

/* Globals */
int ScreenX = 0;
int ScreenY = 0;
BYTE* ScreenData = 0;
void ScreenCap() 
{
    HDC hScreen = GetDC(NULL);
    ScreenX = GetDeviceCaps(hScreen, HORZRES);
    ScreenY = GetDeviceCaps(hScreen, VERTRES);
    HDC hdcMem = CreateCompatibleDC(hScreen);
    HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, ScreenX, ScreenY);
    HGDIOBJ hOld = SelectObject(hdcMem, hBitmap);
    BitBlt(hdcMem, 0, 0, ScreenX, ScreenY, hScreen, 0, 0, SRCCOPY);
    SelectObject(hdcMem, hOld);
    BITMAPINFOHEADER bmi = {0};
    bmi.biSize = sizeof(BITMAPINFOHEADER);
    bmi.biPlanes = 1;
    bmi.biBitCount = 32;
    bmi.biWidth = ScreenX;
    bmi.biHeight = -ScreenY;
    bmi.biCompression = BI_RGB;
    bmi.biSizeImage = 0;// 3 * ScreenX * ScreenY;
    if(ScreenData)
        free(ScreenData);
    ScreenData = (BYTE*)malloc(4 * ScreenX * ScreenY);
    GetDIBits(hdcMem, hBitmap, 0, ScreenY, ScreenData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
    ReleaseDC(GetDesktopWindow(),hScreen);
    DeleteDC(hdcMem);
    DeleteObject(hBitmap);
}
inline int PosB(int x, int y) 
{
    return ScreenData[4*((y*ScreenX)+x)];
}
inline int PosG(int x, int y) 
{
    return ScreenData[4*((y*ScreenX)+x)+1];
}
inline int PosR(int x, int y) 
{
    return ScreenData[4*((y*ScreenX)+x)+2];
}
bool ButtonPress(int Key)
{
    bool button_pressed = false;
    while(GetAsyncKeyState(Key))
        button_pressed = true;
    return button_pressed;
}
int main() 
{
    while (true) 
    {
       if (ButtonPress(VK_SPACE))
       {  
          // Print out current cursor position
          POINT p;
          GetCursorPos(&p);
          printf("X:%d Y:%d n",p.x,p.y);
          // Print out RGB value at that position
          std::cout << "Bitmap: r: " << PosR(p.x, p.y) << " g: " << PosG(p.x, p.y) << " b: " << PosB(p.x, p.y) << "n";
       } else if (ButtonPress(VK_ESCAPE))
       {
          printf("Quitn");
          break;
       } else if (ButtonPress(VK_SHIFT))
       {
          ScreenCap();
          printf("Capturedn");
       }
    }
    system("PAUSE");
    return 0;
}

您的图像大小指定为像素,它应该指定为字节

**bmi.biSizeImage = ScreenX * ScreenY;**
**bmi.biBitCount = 24;**
bmi.biWidth = ScreenX;
bmi.biHeight = -ScreenY;
**bmi.biCompression = BI_RGB;**

biSizeImage它定义的单位是字节并且你指定RGB每像素3字节

http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376 (v = vs.85) . aspx

biSizeImage图像的大小,以字节为单位。对于BI_RGB位图,这个值可以设置为0。