从RGB BMP创建灰度BMP

Create greyscale BMP from RGB BMP

本文关键字:BMP 灰度 创建 RGB      更新时间:2023-10-16

我有24位图像,我读取位图并将其转换为灰度级,然后像8位一样保存。

RGBTRIPLE temp;
unsigned char t;
...
t = (temp.rgbtBlue * 0.114 + temp.rgbtGreen * 0.587 + temp.rgbtRed * 0.299);
fwrite(&t, sizeof(UCHAR), 1, newFile);

在那个图像没有打开之后,我明白我必须更改标题。我尝试更改文件的大小和标头中位图的大小,但没有成功。

BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
...
bfh.bfSize = sizeof(UCHAR) * img.Width * img.Height + bfh.bfOffBits;
bih.biSizeImage = sizeof(UCHAR) * img.Width * img.Height;
bih.biCompression = BI_BITFIELDS;
bih.biBitCount = 8;

我需要更改什么来保存像8位BMP这样的图像?

实际上,最简单的方法是不更改标头中的任何内容。读取3个值(RGB),使用标准PAL/NTSC公式将其转换为灰度,然后可以将计算的灰度值输出3次。这样,您可以再次获得1个像素,但更改了值。

仅仅更改标题是行不通的,因为对于一个8位的颜色索引图像,您还需要提供一个颜色索引映射——调色板。此外,根据原始图像的大小,您可能需要更改每行的步幅(这就是它的名称——谷歌也是您的朋友!)。

正如Mark Setchell所说,BI_BITFIELDS不是您所需要的(BMP上的维基百科)。将BI_RGB用于真彩色或彩色索引图像;其他的值是非常专业化的,我从来没有在"野外"见过它们。

如果使用Gdiplus类位图的成员函数ConvertFormat ,会容易得多

void GrayScale(Bitmap* bmp)
{
    void* p = malloc(sizeof(Gdiplus::ColorPalette) + 255 * sizeof(ARGB));
    Gdiplus::ColorPalette *cpal = (Gdiplus::ColorPalette*)p;
    for (int i = 0; i < 256; i++) cpal->Entries[i] = Color::MakeARGB(0, i, i, i);
    cpal->Flags = PaletteFlagsGrayScale;
    cpal->Count = 256;
    bmp->ConvertFormat(PixelFormat8bppIndexed, DitherTypeSolid, PaletteTypeCustom, cpal, 0);
    free(p);
}