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 ответов
помимо хороших ответов, уже данных, вот пример как чтобы получить простую структуру массива ходить. (Вы можете использовать, например,ГОЗ' код для итерации.)
выберите пункт DIB_RGB_COLORS
как флаг для uUsage
и создал BITMAPINFO
структура и BITMAPINFOHEADER
структура в нем содержится. Когда вы установите biClrUsed
и biClrImportant
к нулю, есть таблица цветов "нет", поэтому вы можете прочитать пиксели растрового изображения, которое вы получаете от GetDIBits
как последовательность значений RGB. Используя 32
как разрядность (biBitCount
) устанавливает структуру данных в соответствии с MSDN:
растровое изображение имеет максимум 2^32 цветов. Если
biCompression
членBITMAPINFOHEADER
isBI_RGB
, thebmiColors
членBITMAPINFO
isNULL
. Каждый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
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.
}
}
Это не так просто. Ваш алгоритм будет зависеть от глубины цвета изображения. Если это 256 или меньше, у вас не будет цветов пикселей, но они будут в палитре цветов. 16-битные пиксели могут быть RGB555 или RGB565, 24-битные изображения будут RGB888, а 32-битные изображения будут RGBA или ARGB. Вам понадобится BITMAPINFOHEADER, чтобы узнать.
Как только вы узнаете, пиксельные данные будут просто массивом ширины размера * высота * (BitsPerPixel / 8)
в ссылке, которую вы публикуете, вы создаете 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-битном режиме его сложнее
некоторый сюрприз от MSDN:
таблица состоит из массива структур данных RGBQUAD. (Таблица для формата BITMAPCOREINFO строится с данными RGBTRIPLE структура.) Красный, зеленый и синий байты в обратном порядке (красный меняет позицию на синюю) из соглашения Windows.
Итак, цвета находятся в порядке BGR в памяти после GetDIBits ()