2013-04-19 15 views
6

Bitmap'lerle çalışmak benim için çok yeni, dolayısıyla okuduğum çevrimiçi eğiticiler ve stratejilerle gerçekten uğraştım. Temel olarak amacım, ekranı belirli bir RGB değeri için taramaktır. Bunu yapmak için adımların, ekranı bir hBitmap'te yakalamak ve daha sonra içinden tarayabileceğim bir dizi RGB değeri üretmek olduğuna inanıyorum.C++ RGB'yi hBitmap'den alma

Başlangıçta GetPixel ile başladım, ancak bu çok yavaş. Çözüm, RGB değerleri dizisini üreten GetDIBits'i kullanmaktı. Sorun, bunun yerine garip ve muhtemelen rastgele RGB değerlerini döndürmesidir. Aşağıdaki kod ile bunu test

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

:

ben başka öğretici bulunamadı Aşağıdaki kodu kullanıyorum. ScreenCap'i çağırmak için Shift'e basıyorum ve ardından imlecimi istenen konuma taşıyorum ve RGB değerinin o konumda ne olduğunu görmek için Space'e basıyorum. Tamamen deliriyor muyum?

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

Sen RGB talebinde, ancak kod BGR gibi verileri tedavi gibi görünüyor . –

+0

Okuduğum şeyden, GetDIBits'in doğasının bu sırayla döndüğüne inanıyorum. Ama sanırım, tüm r = g = b olan tamamen siyah/beyaz bir ekranda test etsem bile, rgb değerlerinin hala rasgele olduğu görülüyor. Bu yüzden aslında beyaz olduğunda siyahı ve bazen siyah olduğunda beyazı bildirir. – Mike

+0

[GetDIBits ve X, Y kullanarak pikseller arasında döngü] olası bir kopyası (http://stackoverflow.com/questions/3688409/getdibits-and-loop-through-pixels-using-xy) – sashoalm

cevap

7

sorunun ekran aslında 32bit derin değil 24. Aşağıdaki kod size ihtiyacınız sonuç verecektir olmasıdır:

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

[Görünüşe göre bir bellek sızıntısı vardı Bu çözümde hata] (http://www.reddit.com/r/programming/comments/24vitp/question_quality_is_dropping_on_stack_overflow/chbcw7i), [ama şimdi düzeltildi] (http://stackoverflow.com/revisions/16115730/2) . –

0

Resminiz piksel belirtilen, bu bayt belirtilmelidir

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

biSizeImage onun tanımlanmış birimler bayt ve size 3 bayt başına RGB belirtiyorsanız piksel. http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx

biSizeImage boyutu

, görüntünün bayt, içinde. Bu, BI_RGB bitmapleri için sıfır olarak ayarlanabilir.

İlgili konular