2013-04-19 3 views
6

비트 맵을 사용하는 것은 나에게 매우 새로운 것이므로 내가 읽은 온라인 자습서와 전략에 정말로 고심하고 있습니다. 기본적으로 내 목표는 특정 RGB 값의 화면을 스캔하는 것입니다. 이 작업을 수행하는 단계는 hBitmap에서 화면을 캡처 한 다음 스캔 할 수있는 RGB 값의 배열을 생성하는 것입니다.C++ hBitmap에서 RGB 가져 오기

원래 GetPixel로 시작했지만 그 속도는 매우 느립니다. 해결책은 RGB 값의 배열을 생성하는 GetDIBits를 사용하는 것이 었습니다. 문제는 이상한 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("Quit\n"); 
     break; 
    } else if (GetAsyncKeyState(VK_SHIFT)){ 
     ScreenCap(); 
     printf("Captured\n"); 
    } 
} 

system("PAUSE"); 
return 0; 
} 
+0

당신은 RGB를 요청,하지만 코드는 BGR로 데이터를 처리하는 것 같다 . –

+0

내가 읽은 것부터, 나는 GetDIBits의 본질이 그것들을 순서대로 반환한다고 믿는다. 그러나 나는 모든 r = g = b 인 완전 흑백 스크린에서 테스트를하더라도 여전히 rgb 값이 무작위 인 것으로보아야한다는 것을 지적해야합니다. 따라서 실제로는 흰색 인 경우 검정색을, 검정색 인 경우 흰색으로 표시합니다. – Mike

+0

가능한 [GetDIBits 및 X, Y]를 사용하여 픽셀을 반복 루프 (http://stackoverflow.com/questions/3688409/getdibits-and-loop-through-pixels-using-xy) – sashoalm

답변

7

문제는 화면이 실제로 32 비트 깊은하지 (24) 아래의 코드는 당신이 필요로하는 결과를 줄 것이다라는 것이다 :

/* Globals */ 
int ScreenX = 0; 
int ScreenY = 0; 
BYTE* ScreenData = 0; 

void ScreenCap() 
{ 
    HDC hScreen = GetDC(GetDesktopWindow()); 
    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; 
} 
+1

[분명히 메모리 누수가 발생했습니다 이 솔루션의 버그] (http://www.reddit.com/r/programming/comments/24vitp/question_quality_is_dropping_on_stack_overflow/chbcw7i), [지금은 고쳐졌습니다] (http://stackoverflow.com/revisions/16115730/2) . –

0

이미지 크기가 픽셀에 지정되어, 그것은 바이트로 지정해야

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

biSizeImage 정의 된 단위 바이트이고, 당신이 3 바이트 당 RGB를 지정하는 픽셀. http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx

biSizeImage 크기

화상 바이트, 있다. BI_RGB 비트 맵의 ​​경우이 값을 0으로 설정할 수 있습니다.

관련 문제