2013-04-19 26 views
6

Làm việc với bitmap rất mới đối với tôi vì vậy tôi đã thực sự đấu tranh với các hướng dẫn và chiến lược trực tuyến mà tôi đã đọc qua. Về cơ bản mục tiêu của tôi là quét màn hình cho một giá trị RGB cụ thể. Tôi tin rằng các bước để làm điều này là chụp màn hình trong hBitmap và sau đó tạo ra một mảng các giá trị RGB từ nó mà tôi có thể quét qua.C++ Bắt RGB từ hBitmap

Ban đầu tôi bắt đầu với GetPixel nhưng điều đó rất chậm. Giải pháp là sử dụng GetDIBits tạo ra mảng giá trị RGB. Vấn đề là nó trả về các giá trị RGB ngẫu nhiên và có thể ngẫu nhiên thay thế.

Tôi đang sử dụng đoạn mã sau đó tôi thấy từ hướng dẫn khác:

/* 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)]; 
} 

tôi thử nghiệm này với đoạn mã sau. Tôi nhấn Shift để gọi ScreenCap và sau đó tôi di chuyển con trỏ đến vị trí mong muốn và nhấn Space để xem giá trị RGB ở vị trí đó. Tôi có hoàn toàn không?

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

Bạn đang yêu cầu RGB, nhưng mã của bạn dường như được coi tài liệu như BGR . –

+0

Từ những gì tôi đã đọc, tôi tin rằng bản chất của GetDIBits trả về chúng theo thứ tự đó. Nhưng tôi đoán tôi nên chỉ ra rằng ngay cả khi tôi thử nghiệm trên một màn hình hoàn toàn màu đen/trắng, nơi tất cả r = g = b, các giá trị rgb vẫn có vẻ là ngẫu nhiên. Vì vậy, nó sẽ báo cáo màu đen khi nó thực sự trắng, và trắng khi nó thực sự là màu đen đôi khi. – Mike

+0

có thể trùng lặp của [GetDIBits và lặp qua pixel bằng X, Y] (http://stackoverflow.com/questions/3688409/getdibits-and-loop-through-pixels-using-xy) – sashoalm

Trả lời

7

Vấn đề là màn hình của bạn thực sự là 32bits sâu không 24. Đoạn mã dưới đây sẽ cung cấp cho bạn kết quả bạn cần:

/* 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

[Dường như đã có rò rỉ bộ nhớ lỗi trong giải pháp này] (http://www.reddit.com/r/programming/comments/24vitp/question_quality_is_dropping_on_stack_overflow/chbcw7i), [nhưng nó đã được sửa ngay] (http://stackoverflow.com/revisions/16115730/2) . –

0

kích thước hình ảnh của bạn được quy định tại pixel, nó nên được quy định tại byte

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

biSizeImage đơn vị quy định của nó là byte và bạn đang xác định RGB 3 byte cho mỗi pixel.

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

biSizeImage Kích thước, trong byte, của hình ảnh. Điều này có thể được đặt thành 0 cho bitmap BI_RGB.

Các vấn đề liên quan