Как преобразовать растровое изображение в оттенки серого по интенсивности пикселей с помощью GDI?
Я ищу простое решение, как преобразовать 32-битное растровое изображение в оттенки серого с помощью GDI (не GDI+). Есть ли возможность, например, изменить палитру растрового изображения или что-то еще ?
Конечно, в Delphi есть много примеров, таких как Этот, но я ищу функцию WinAPI, которая делала бы это без итерации по строкам.
2 ответа:
Я не нашел ни одной функции GDI, делающей это. Самый простой способ, как отметил Дэвид в своем комментарии, - сканировать каждую строку и вычислять цвета пикселей. То, что вы ищете, вероятно, является
luminance
Формула.Существует несколько вариантов этой формулы, и в следующем примере я использовал тот, который рекомендован
ITU
, видишьthis document
раздел 2.5.1. Как я где-то нашел, эта формула используется, например, даже хорошо известным Adobe Photoshop. Следующий пример кода поддерживает и ожидает только 24-битные растровые изображения формата pixel в качестве входных данных:procedure BitmapGrayscale(ABitmap: TBitmap); type PPixelRec = ^TPixelRec; TPixelRec = packed record B: Byte; G: Byte; R: Byte; end; var X: Integer; Y: Integer; Gray: Byte; Pixel: PPixelRec; begin for Y := 0 to ABitmap.Height - 1 do begin Pixel := ABitmap.ScanLine[Y]; for X := 0 to ABitmap.Width - 1 do begin Gray := Round((0.299 * Pixel.R) + (0.587 * Pixel.G) + (0.114 * Pixel.B)); Pixel.R := Gray; Pixel.G := Gray; Pixel.B := Gray; Inc(Pixel); end; end; end;
Вы можете создать раздел DIB с палитрой, 8 бит на пиксель и 256 цветов, а также инициализировать палитру до оттенков серого { 0, 0, 0 }, { 1, 1, 1 }, ... { 255, 255, 255 }.
Один GDI
BitBlt
в этом растровом изображении будет серым ваше исходное изображение. Вот фрагмент кода (в C++, ATL и WTL - но вы должны понять идею).CWindowDC DesktopDc(NULL); CDC BitmapDc; ATLVERIFY(BitmapDc.CreateCompatibleDC(DesktopDc)); CBitmap Bitmap; CTempBuffer<BITMAPINFO> pBitmapInfo; const SIZE_T nBitmapInfoSize = sizeof (BITMAPINFO) + 256 * sizeof (RGBQUAD); pBitmapInfo.AllocateBytes(nBitmapInfoSize); ZeroMemory(pBitmapInfo, nBitmapInfoSize); pBitmapInfo->bmiHeader.biSize = sizeof pBitmapInfo->bmiHeader; pBitmapInfo->bmiHeader.biWidth = 320; pBitmapInfo->bmiHeader.biHeight = 240; pBitmapInfo->bmiHeader.biPlanes = 1; pBitmapInfo->bmiHeader.biBitCount = 8; pBitmapInfo->bmiHeader.biCompression = BI_RGB; pBitmapInfo->bmiHeader.biSizeImage = 240 * 320; pBitmapInfo->bmiHeader.biClrUsed = 256; pBitmapInfo->bmiHeader.biClrImportant = 256; for(SIZE_T nIndex = 0; nIndex < 256; nIndex++) { pBitmapInfo->bmiColors[nIndex].rgbRed = (BYTE) nIndex; pBitmapInfo->bmiColors[nIndex].rgbGreen = (BYTE) nIndex; pBitmapInfo->bmiColors[nIndex].rgbBlue = (BYTE) nIndex; } Bitmap.Attach(CreateDIBSection(DesktopDc, pBitmapInfo, 0, DIB_RGB_COLORS, NULL, 0)); ATLVERIFY(Bitmap); BitmapDc.SelectBitmap(Bitmap); //////////////////////////////////////////////// // This is what greys it out: ATLVERIFY(BitBlt(BitmapDc, 0, 0, 320, 240, DesktopDc, 0, 0, SRCCOPY)); //////////////////////////////////////////////// ATLVERIFY(BitBlt(DesktopDc, 0, 240, 320, 240, BitmapDc, 0, 0, SRCCOPY));