【问题标题】:How to make 8-bit bitmap appear as monochrome in C++?如何使 8 位位图在 C++ 中显示为单色?
【发布时间】:2013-01-30 08:45:01
【问题描述】:

当我像这样设置和创建 24 位位图时:

   //fileheader
    BITMAPFILEHEADER* bf = new BITMAPFILEHEADER;
    bf->bfType = 0x4d42;
    bf->bfSize = 6054400 + 54;
    bf->bfOffBits = 54;

    //infoheader
    BITMAPINFOHEADER* bi = new BITMAPINFOHEADER;
    bi->biSize = 40;
    bi->biWidth = 2752;
    bi->biHeight = -733;
    bi->biPlanes = 1;
    bi->biBitCount = 24;
    bi->biCompression = 0;
    //bi->biSizeImage = 6054400;
    bi->biXPelsPerMeter = 2835;
    bi->biYPelsPerMeter = 2835;
    bi->biClrUsed = 0;
    bi->biClrImportant = 0;

    pFrame->GetImage(m_imageData);

    //
    //create bitmap...
    //(hbit is a global variable)

    BITMAPINFO* bmi;
    bmi = (BITMAPINFO*)bi; 
    HDC hdc = ::GetDC(NULL);

    hbit = CreateDIBitmap(hdc, bi, CBM_INIT, m_imageData, bmi, DIB_RGB_COLORS);

我得到这样的输出图像:

但是当我将 bitcount 从 24 更改为 8(这也允许 3 倍图像大小,允许我从 733 宽度变为图像的自然宽度 2200)时,我得到了这样的图像(以及很多不稳定性):

我的输出如下所示:

    BITMAP* bi = new BITMAP;
    CBitmap bmp;
    bmp.Attach(hbit);
    CClientDC dc(pWnd);
    CDC bmDC;
    bmDC.CreateCompatibleDC(&dc);
    CBitmap *pOldbmp = bmDC.SelectObject(&bmp);
    bmp.GetBitmap(bi);
    dc.BitBlt(384,26,bi->bmWidth/3,bi->bmHeight,&bmDC,0,0,SRCCOPY);
    //note: if bitcount is 8, height and width need to be /3, 
          //if 24, only width gets /3 
    bmDC.SelectObject(pOldbmp);

    //explicitly delete everything just to be safe
    delete bi;
    DeleteObject(bmp);
    DeleteObject(dc);
    DeleteObject(pOldbmp);
    DeleteObject(bmDC);

所以我的问题是:

  • 为什么当我从 24 切换到 8 时会发生这种情况?
  • 有没有一种简单的方法可以将图像输出为单色而不是彩色?

最后一件事:

我的同事很久以前为类似的问题编写了此功能,但他说我也许可以使用它。不幸的是,我无法让它工作:

void CopyMono8ToBgrx(byte* pDestBlue, byte* pDestGreen, byte *pDestRed, byte* pDestAlpha)
    {
        byte*               pSrc;
        byte*               pSrcEnd;

        pSrc = ( byte* ) m_imageData;
        pSrcEnd = pSrc + ( 2752*2200 );

        while ( pSrc < pSrcEnd )
        {
            byte data = *pSrc;

            *pDestBlue  = data;
            *pDestGreen = data;
            *pDestRed   = data;
            *pDestAlpha = 255;  // alpha is always 255 (fully opaque)

            pSrc++;
            pDestBlue   += 4;
            pDestGreen  += 4;
            pDestRed    += 4;
            pDestAlpha  += 4;
        }
    }

【问题讨论】:

  • 看起来您的颜色图(调色板)可能搞砸了?

标签: c++ image bitmap gdi


【解决方案1】:

您应该创建一个调色板。试试这个:

struct BITMAPINFO256 {
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD bmiColors[256];
} bmi;
memset(&bmi, 0, sizeof(BITMAPINFO256));
bmi.bmiHeader.biSize = 40;
bmi.bmiHeader.biWidth = 2752;
bmi.bmiHeader.biHeight = -733;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 8;
bmi.bmiHeader.biCompression = 0;
bmi.bmiHeader.biXPelsPerMeter = 2835;
bmi.bmiHeader.biYPelsPerMeter = 2835;
bmi.bmiHeader.biClrUsed = 256;
bmi.bmiHeader.biClrImportant = 0;
for (unsigned int i = 0; i < 256; i++) {
    bmi.bmiColors[i].rgbRed   = i;
    bmi.bmiColors[i].rgbGreen = i;
    bmi.bmiColors[i].rgbBlue  = i;
}

然后当你调用CreateDIBitmap时,它会变成:

hbit = CreateDIBitmap(hdc, &bmi.bmiHeader, CBM_INIT, m_imageData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);

还请注意,您还应该小心增加BITMAPFILEHEADER 中的偏移量,以便它表示在实际像素数据之前定义了调色板(昨天我因此很难过,请参阅@987654321 @):

bf->bfOffBits = 54 + sizeof(RGBQUAD)*256;

对于你同事写的那个函数:最好使用Luminance 将颜色转换为等效灰度:

希望这会有所帮助:)

【讨论】:

  • 嗨,我正在使用此代码,它提供灰度图像,但图像垂直翻转。我使用正高度,因为负高度给出纯黑色输出。请告诉我如何获得正确的图像。
  • @Khushboo:将其作为一个新问题发布,提供更多详细信息,并在此处放置该答案的链接,并写下解决方案基于此。很难说可能是这样的问题:)
【解决方案2】:

每像素 8 位图像假设调色板遵循BITMAPINFOHEADER 结构(请参阅BITMAPINFO::bmiColors)。如果您将调色板设置为 256 灰度,则图像将变为 8 bpp 灰度。现在它是随机颜色的颜色。

您引用的函数 CopyMono8ToBgrx 创建全彩色位图,带有灰色的单个像素 (R=G=B)。

【讨论】:

猜你喜欢
  • 2011-04-24
  • 1970-01-01
  • 1970-01-01
  • 2012-03-25
  • 2020-05-07
  • 1970-01-01
  • 2013-04-03
  • 2011-04-25
  • 1970-01-01
相关资源
最近更新 更多