GetDIBits и цикл по пикселям, используя X, Y

Я хватаю часть экрана и сканирую пиксели для определенного цветового диапазона.

Я посмотрел пример захвата изображения в MSDN и знаю, как использовать функции.

Я могу получить биты в массив, но я не уверен, как это сделать таким образом, чтобы я мог проходить по нему, как изображение. Псевдо-пример (который, я уверен, далеко):

for ( x = 1; x <= Image.Width; x += 3 )
{
    for ( y = 1; y <= Image.Height; y += 3 )
    {
        red = lpPixels[x];
        green = lpPixels[x + 1];
        blue = lpPixels[x + 2];
    }
}

Это в основном то, что я хочу сделать, поэтому, если красный, синий и зеленый - это определенный цвет, я буду знать, какова его координата (x, y) на изображении.

Я просто не знаю, как использовать GetDIBits таким образом, и как правильно настроить массив для достижения этой цели.

5 ответов

Решение

Помимо хороших ответов, вот пример того, как получить простую структуру массива. (Вы можете использовать, например , код Goz для итерации.)

Ссылка GetDIBits @ MSDN

Вы должны выбрать DIB_RGB_COLORS как флаг для uUsage и настроить BITMAPINFO структура и BITMAPINFOHEADER структура, которую он содержит. Когда вы установите biClrUsed а также biClrImportant в ноль, нет таблицы цветов "нет", так что вы можете прочитать пиксели растрового изображения, которое вы получаете GetDIBits как последовательность значений RGB. С помощью 32 как количество бит (biBitCount) устанавливает структуру данных в соответствии с MSDN:

Растровое изображение имеет максимум 2^32 цветов. Если biCompression член BITMAPINFOHEADER является BI_RGB, bmiColors член BITMAPINFO является NULL, каждый DWORD в массиве растровых изображений представляет относительную интенсивность синего, зеленого и красного соответственно для пикселя. Старший байт в каждом DWORD не используется

С МС LONG ровно 32 бит (размер DWORD), вам не нужно обращать внимание на отступы (как описано в разделе " Примечания").

Код:

HDC hdcSource = NULL; // the source device context
HBITMAP hSource = NULL; // the bitmap selected into the device context

BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);

// Get the BITMAPINFO structure from the bitmap
if(0 == GetDIBits(hdcSource, hSource, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS))
{
    // error handling
}

// create the pixel buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];

// We'll change the received BITMAPINFOHEADER to request the data in a
// 32 bit RGB format (and not upside-down) so that we can iterate over
// the pixels easily. 

// requesting a 32 bit image means that no stride/padding will be necessary,
// although it always contains an (possibly unused) alpha channel
MyBMInfo.bmiHeader.biBitCount = 32;
MyBMInfo.bmiHeader.biCompression = BI_RGB;  // no compression -> easier to use
// correct the bottom-up ordering of lines (abs is in cstdblib and stdlib.h)
MyBMInfo.bmiHeader.biHeight = abs(MyBMInfo.bmiHeader.biHeight);

// Call GetDIBits a second time, this time to (format and) store the actual
// bitmap data (the "pixels") in the buffer lpPixels
if(0 == GetDIBits(hdcSource, hSource, 0, MyBMInfo.bmiHeader.biHeight,
                  lpPixels, &MyBMInfo, DIB_RGB_COLORS))
{
    // error handling
}
// clean up: deselect bitmap from device context, close handles, delete buffer

GetDIBits возвращает одномерный массив значений. Для растрового изображения шириной M пикселей и N пикселей и использующего 24-битный цвет, первые (M*3) байты будут первой строкой пикселей. Это может сопровождаться некоторыми байтами заполнения. Это зависит от BITMAPINFOHEADER. Обычно для заполнения используется ширина, кратная 4 байтам. Таким образом, если ваше растровое изображение имеет ширину 33 пикселя, на самом деле в строке будет (36*3) байт.

Этот "пиксели плюс отступы" называется "шагом". Для растровых изображений RGB вы можете рассчитать шаг с помощью: stride = (biWidth * (biBitCount / 8) + 3) & ~3, где biWidth а также biBitCount взяты из BITMAPINFOHEADER.

Я не уверен, как вы хотите пройти массив. Если вы хотите перейти попиксельно от верхнего левого угла к нижнему правому (при условии, что это растровое изображение сверху вниз):

for (row = 0; row < Image.Height; ++row)
{
    int rowBase = row*stride;
    for (col = 0; col < Image.Width; ++col)
    {
        red = lpPixels[rowBase + col];
        // etc.
    }
}

В размещенной вами ссылке вы создаете 32-битное растровое изображение, поэтому я предполагаю, что вы читаете из 32-разрядного растрового изображения (это предположение может быть неверным).

Поэтому изменение вашего цикла на следующее должно работать:

char* pCurrPixel = (char*)lpPixels;
for ( y = 0; y < Image.Height; y++ )
{
    for ( x = 0; x < Image.Width; x++ )
    {
        red = pCurrPixel[0];
        green = pCurrPixel[1];
        blue = pCurrPixel[2];

        pCurrPixel += 4;
    }
}

Что нужно иметь в виду:

1. Массивы 0 основаны на C / C++
2. Вы шагали по 3 пикселя по горизонтали и вертикали каждый раз. Это означало, что вы не посещаете каждый пиксель.
3. Растровое изображение, как правило, организовано таким образом, что есть "высота" пролетов "ширина" пикселей. Поэтому вы должны пройти через каждый пиксель в промежутке и затем перейти к следующему промежутку.
4. Как уже отмечалось, убедитесь, что вы правильно читаете пиксели. в 16-битном режиме его сложнее

Это не так просто. Ваш алгоритм будет зависеть от глубины цвета изображения. Если он равен 256 или меньше, у вас не будет пиксельных цветов, но он превращается в палитру цветов. 16-битные пиксели могут быть RGB555 или RGB565, 24-битные изображения будут RGB888, а 32-битные изображения будут RGBA или ARGB. Вам понадобится BITMAPINFOHEADER, чтобы узнать.

Как только вы узнаете, данные пикселей будут просто массивом ширины * высоты * (BitsPerPixel / 8)

Некоторый сюрприз от MSDN:

Таблица состоит из массива структур данных RGBQUAD. (Таблица для формата BITMAPCOREINFO построена с использованием структуры данных RGBTRIPLE.) Красный, зеленый и синий байты расположены в обратном порядке (позиция красного цвета с синим) из соглашения Windows.

Итак, цвета в порядке BGR в памяти после GetDIBits()

Другие вопросы по тегам