简体   繁体   English

如何使用GDI按像素强度将位图转换为灰度?

[英]How to convert bitmap to grayscale by pixel intensity using GDI?

I'm looking for the simple solution of how to convert the 32-bit bitmap to grayscale using GDI (not GDI+). 我正在寻找如何使用GDI(而不是GDI +)将32位位图转换为灰度的简单解决方案。 Is there a possibility eg by changing the bitmap's pallete or something ? 是否有可能通过更改位图的托盘或其他东西?

Of course there is plenty of examples in Delphi like this one , but I'm looking for a WinAPI function which would do this without iteration through the lines. 当然Delphi中有很多像这样的例子,但是我正在寻找一个WinAPI函数,它可以在没有迭代的情况下执行此操作。

I haven't found any single GDI function doing this. 我没有找到任何单一的GDI功能。 The easiest way, as David mentioned in his comment, is to scan each line and compute the pixel colors. 大卫在评论中提到的最简单的方法是扫描每一行并计算像素颜色。 What you are looking for is probably the luminance formula. 您正在寻找的可能是luminance公式。

There are few variations of this formula and in the following example I've used the one recommended by the ITU , see this document section 2.5.1. 该公式的变化很少,在下面的例子中,我使用了ITU建议的那个,参见this document第2.5.1节。 As I found somewhere, this formula is used eg even by well known Adobe Photoshop. 正如我在某处找到的那样,这个公式甚至可以用于熟知的Adobe Photoshop。 The following code example supports and expects only 24-bit pixel format bitmaps as an input: 以下代码示例仅支持并期望24位像素格式位图作为输入:

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;

You can create a paletted DIB Section, 8 bits per pixel and 256 colors, and initialize palette to shades of grey { 0, 0, 0 }, { 1, 1, 1 }, ... { 255, 255, 255 }. 您可以创建一个调色板DIB截面,每像素8位和256种颜色,并将调色板初始化为灰色{0,0,0},{1,1,1},... {255,255,255}的阴影。

A single GDI BitBlt into this bitmap will grey your original image out. 此位图中的单个GDI BitBlt将使原始图像变灰。 Here is the code snippet (in C++, ATL and WTL - but you should get the idea). 这是代码片段(用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));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM