C语言 将BMP转换为2d矩阵,混淆了颜色



我试图创建一个2d数组,其中包含图像中每个像素的RGB值,我创建了原始图像的副本,以检查图像是否相似,我得到的输出主要是灰色像素。(我尽量只使用标准库)。

这是我使用的结构体

typedef struct { //bmp file values struct
int width;
int height;
} image_t;
typedef struct { //pixel color
unsigned char r;
unsigned char g;
unsigned char b;
} color_t;

主要
int main() {
int i, j;
color_t** matrix;
static image_t image;
if ((LoadSprite(&image, BMP)) != 0) {
printf_s("Failed to load file: " %s"", BMP);
return -1;
}
matrix = malloc(sizeof(color_t*) * image.height); // allocate memory to image pixel matrix
for (i = 0;i < image.height;i++) {
matrix[i] = malloc(sizeof(color_t) * image.width);
}
imgtrx(matrix, image, BMP);
CreateBMP(BMPCPY, matrix, image.height, image.width);

return 0;
}

函数imgtrx本质上是将RGB像素值根据图像高度&宽度

void imgtrx(color_t** mtrx, image_t image, char* filename) {
int val, t, i = 0, j, k = 0;
FILE* file;
val = fopen_s(&file, filename, "rt");
//fseek(file, 54, SEEK_SET);
fseek(file, 10, SEEK_SET);
fread(&t, 1, 4, file);     //reads the offset and puts it in t
fseek(file, t, SEEK_SET);
int  p, e;
for ( i = 0; i < image.width; i++)
{
for (j = 0;j < image.height;j++) {
fread(&mtrx[i][j].r, 8, 1, file);
fread(&mtrx[i][j].g, 8, 1, file);
fread(&mtrx[i][j].b, 8, 1, file);
}
}

fclose(file);
return 0;
}

下面的函数将二维数组转换为一维数组并写入一个BMP副本

void CreateBMP(char* filename, color_t** matrix, int height, int width) 
{
int i, j;
int padding, bitmap_size;
color_t* wrmat;
wrmat = malloc(sizeof(color_t) * height * width);
for (i = 0;i < height;i++) {
for (j = 0;j < width;j++) {
wrmat[i + j] = matrix[i][j];
}
}
if (((width * 3) % 4) != 0) {
padding = (width * 3) + 1;
}
else
{
padding = width * 3;
}
bitmap_size = height * padding * 3;
char tag[] = { 'B', 'M' };
int header[] = {
0x3a, 0x00, 0x36,
0x28,                // Header Size
width, height,       // Image dimensions in pixels
0x180001,            // 24 bits/pixel, 1 color plane
0,                   // BI_RGB no compression
0,                   // Pixel data size in bytes
0x002e23, 0x002e23,  // Print resolution
0, 0,                // No color palette
};
header[0] = sizeof(tag) + sizeof(header) + bitmap_size;
FILE* fp;
fopen_s(&fp, filename, "w+");
fwrite(&tag, sizeof(tag), 1, fp);
fwrite(&header, sizeof(header), 1, fp); //write header to disk
fwrite(wrmat, bitmap_size * sizeof(char), 1, fp);
fclose(fp);
fclose(fp);
free(wrmat);
}

请注意,BMP文件可以有不同的像素格式,详见Microsoft手册中Win32和OS/2的BITMAPINFOHEADER结构族。

From your "all grey"结果,我怀疑您正在尝试将小于24bpp的格式解释为RGB值,或者在读取文件的像素区域时遇到技术问题。

所以要做你想做的事情,你的代码需要读取BITMAPINFOHEADER结构的前4个字节,使用它来确定结构版本,然后读取BITMAPINFOHEADER的其余部分来确定像素数组格式和位于BITMAPINFOHEADER和实际像素之间的调色板/颜色信息结构的大小/格式。

还记得将任何头字段(包括您已经解析的偏移字段)从小端序磁盘格式转换为运行时CPU使用的任何格式。请注意"负高度值"的使用。表示反扫描线顺序是非常常见的,因为大多数PC和电视硬件首先存储左上角的像素,而正高度BMP文件首先存储左下角的像素。

需要注意的BITMAPINFOHEADER结构的版本如下:2. BITMAPCOREHEADER(来自1980年代)3.BITMAPINFOHEADER(从Windows 3.00开始)4. BITMAPV4HEADER5. BITMAPV5HEADER(注意文档中链接的颜色配置文件描述中有拼写错误)。

需要注意的像素格式有:

  • 1bpp(黑色和白色,强制调色板表示RGB相当于0和1位),如在CGA/EGA/VGA硬件中,每个字节的最重要位是最左边的(本质上是一个大端像素格式)。

  • 4bpp(传统上标准的CGA颜色,但调色板可以为16个可能的像素代码指定任何其他RGB值)。每个字节中最重要的4位是最左边的像素(本质上是一个大端像素格式)。这种格式也用于3bpp EGA硬件像素和2bpp CGA像素,但只使用16个值中的8或4个。

  • 8bpp(强制调色板指示每个字节值如何映射到RGB值)。VGA硬件包括一个专用芯片(RAMDAC),以显示器的全像素速度进行RGB映射。

  • 16bpp(强制性调色板是一个由3个unit32_t位掩码组成的数组,每个像素只返回存储B, G和R值的位,将这些掩码转换为适当的移位值是每个图形程序员的练习)。每个像素是一个小的端序2字节值,与3个掩码值进行和,以获得蓝色,绿色和红色通道值。最常见的位掩码值是5:5:5 15bpp硬件和5:6:5硬件多一个绿色位。

  • 24bpp(没有调色板或掩模数据)每个像素按蓝,绿,红的顺序为3字节,每个像素给出的颜色值为255的一小部分。

  • 32bpp与16bpp相同,只是每个像素值有4个字节。掩码描述的常见格式是Blue,Green,Red,x和Red,Green,Blue,x,其中x可以是0,随机噪声或alpha通道。也有一些文件使用每个颜色通道超过8位来编码HDR图像。如果你正在编写一个通用解码器,你至少需要提取每个颜色通道的8个最重要的位,尽管保留额外的像素位很少是必要的。

在所有这些颜色格式之上,HEADER可以表示多种压缩格式中的任何一种,最明显的是Windows 3使用的BMP RLE4和BMP RLE8压缩格式。x和使用常见的第三方压缩,如JPEG,然而使用BMP格式的包装周围的压缩图像是相当罕见的,这些天,所以你可能不需要担心,然而,它是传统的方式,要求GPU或激光打印机为您解压缩JPEG和PNG文件。在检查其他GDI/GPI API报告安装的驱动程序支持后,通过将内存中的JPEG(来自标准JFIF文件)的内容与内存中的BITMAPINFOHEADER结构一起传递给GDI或GPI API。

最新更新