[C ++从hBitmap获取RGB

问题描述 投票:6回答:2

使用位图对我来说是非常陌生的,所以我一直在努力阅读已读过的在线教程和策略。基本上,我的目标是扫描屏幕上的特定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,然后将光标移动到所需位置,然后按下Space键以查看该位置的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("Quit\n");
      break;
   } else if (GetAsyncKeyState(VK_SHIFT)){
      ScreenCap();
      printf("Captured\n");
   }
}

system("PAUSE");
return 0;
}
c++ rgb pixel scanning hbitmap
2个回答
8
投票

问题是您的屏幕实际上是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("Quit\n");
          break;
       } else if (ButtonPress(VK_SHIFT))
       {
          ScreenCap();
          printf("Captured\n");
       }
    }

    system("PAUSE");
    return 0;
}

0
投票

您的图像大小在像素]中指定,应在字节中指定]

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

biSizeImage

其定义的单位为bytes,您指定的RGB每像素3个字节。

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

biSizeImage图像的大小,以[[bytes为单位。对于BI_RGB位图,可以将其设置为零。

© www.soinside.com 2019 - 2024. All rights reserved.