C ++ Получение RGB из hBitmap

Работа с растровыми изображениями для меня очень новая, поэтому я действительно боролся с онлайн-уроками и стратегиями, которые я прочитал. По сути, моя цель — сканировать экран на предмет определенного значения 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("Quit\n");
break;
} else if (GetAsyncKeyState(VK_SHIFT)){
ScreenCap();
printf("Captured\n");
}
}

system("PAUSE");
return 0;
}

6

Решение

Проблема в том, что ваш экран на самом деле имеет глубину 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;
}
8

Другие решения

Размер вашего изображения указан в пикселей, это должно быть указано в байтов

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

По вопросам рекламы [email protected]