我正在尝试使用代码将 BGR 位图图像转换为灰度,
int main()
{
FILE* fIn;
FILE* fOut;
if (fopen_s(&fIn, "D:\\VBox\\Shared\\images\\sample01.bmp", "rb") != 0) {
return 1;
}
if (fopen_s(&fOut, "D:\\VBox\\Shared\\images\\sample01_gs1.bmp", "wb") != 0) {
return 1;
}
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, fIn); // read the 54-byte header
int32_t width, height;
uint16_t bitperpixl;
memcpy(&width, info + 18, sizeof(int32_t));
memcpy(&height, info + 22, sizeof(int32_t));
memcpy(&bitperpixl, info + 28, sizeof(uint16_t));
int padding = ((width * bitperpixl) / 8) % 4; // which Is 0 for the image which I am using.
fwrite(info, sizeof(unsigned char), 54, fOut);
unsigned char pixel[3]; //bgr
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
fread(pixel, 3, 1, fIn);
unsigned char gray = pixel[2] * 0.3 + pixel[1] * 0.58 + pixel[0] * 0.11;
memset(pixel, gray, sizeof(pixel));
fwrite(&pixel, 3, 1, fOut);
}
fread(pixel, padding, 1, fIn);
fwrite(pixel, padding, 1, fOut);
}
fclose(fOut);
fclose(fIn);
}
创建的文件与输入图像的大小相同。当我尝试使用 Windows 图像查看器打开文件时,它显示图像不受支持或已损坏。
您的代码存在几个主要问题。首先,您不应该假设位图图像数据始终从字节 54 开始。如维基百科“BMP 文件格式”文章的文件结构部分所示,开头为
位图图像文件由固定大小的结构(标题)以及按预定顺序出现的可变大小的结构组成。由于这种文件格式的长期演变,其中一些结构的许多不同版本可以出现在文件中。
还有一个图表显示出现在实际像素阵列之前的可选或半可选部分。相反,要获取它们的起始位置,如位图文件头部分所示,位置从偏移量 10 开始,因此您应该有几行,例如
uint32_t pixelData;
memcpy(&pixelData, info + 10, sizeof(int32_t));
当然,您应该确保在处理像素时从该位置开始读取。
另外,关于处理像素数据本身,请注意,您不能假设它们都是 4 字节块,每个块的前 3 个字节是 RGB 值,然后是填充字节。相反,可能会使用一个颜色表(例如,其中的值是该表的偏移量)。另外,如果使用 Windows BITMAPINFOHEADER,则在偏移量 30 处有一个 4 字节值,指示所使用的压缩方法。维基百科文章描述了各个位的含义。
如果您可以确定输入的 .bmp 文件属于一组特定的有限格式,则可以编写代码来处理这些类型的文件。否则,您应该处理所有这些不同的附加细节。请注意,虽然 BMP 文件格式实际上基本上是最简单的图像格式,但在一般情况下仍然有很多事情需要检查和处理。