GetDIBits и цикл по пикселям, используя X, Y - PullRequest
7 голосов
/ 11 сентября 2010

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

Я посмотрел на пример захвата изображения в 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 ]

12 голосов
/ 11 сентября 2010

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

Ссылка 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 не используется.

Поскольку длина MS 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
9 голосов
/ 11 сентября 2010

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.
    }
}
2 голосов
/ 11 сентября 2010

В ссылке, которую вы публикуете, вы создаете 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-битном режиме его сложнее

2 голосов
/ 11 сентября 2010

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

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

0 голосов
/ 02 ноября 2014

Какой-то сюрприз от MSDN:

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

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

...