【问题标题】:How to write 512x512 pixel array to a bmp file (256 colors and 8 bpp) in c++ using ofstream?如何使用 ofstream 在 c++ 中将 512x512 像素数组写入 bmp 文件(256 色和 8 bpp)?
【发布时间】:2016-04-27 00:37:09
【问题描述】:

让我从介绍开始。我一直在阅读有关位图文件格式(wiki、msdn 等)的信息并研究how to read and write bmp files in c++。我正在用 c++ 编写一个程序,不使用 bmp 库,它可以从 bmp 中提取数据,然后使用该数据创建一个新的 bmp。这样做的目的是查看新的图像文件是否与原始图像文件相同。然后,如果它有效,我可以继续操作提取的数据以执行直方图均衡。

目前,我的程序能够成功地从原始bmp文件中检索位图文件头和位图信息头,然后将其写入新的bmp文件。然后它对颜色表执行相同的操作。问题出现了,或者至少这是我目前认为的问题,与 Pixel 数据有关。看起来它被正确读取,甚至乍一看似乎被正确写入。当我在十六进制编辑器中打开新文件并将其与原始文件进行比较时,可以看到值在偏移量 (h) 630 处开始不同。此外,打开时的新图像看起来不像原始图像。

这是更新后的结构:

#pragma pack(2)                    // Using pragma to force structure format
struct BMPFH                       // Bitmap file header
{
  char HeaderField[2];             // Used to identify the BMP and DIB file is 0x42 0x4D in hexadecimal, same as BM in ASCII
  unsigned int Size_of_BMP;        // size of the BMP file in bytes
  unsigned short Reserved1;        // Reserved; actual value depends on the application that creates the image
  unsigned short Reserved2;        // "                                                                       "
  unsigned int StartAddress;       // offset, i.e. starting address, of the byte where the bitmap image data (pixel array) can be found
};

#pragma pack()
struct DIBH                        // Bitmap information header
{
  unsigned int Size_of_Header;     // Size of this header (40 bytes)
  signed int Width;                // bitmap width in pixels (signed integer)
  signed int Height;               // bitmap height in pixels (signed integer)
  unsigned short Num_of_Planes;    // number of color planes (must be 1)
  unsigned short Num_of_Bits;      // number of bits per pixel, which is the color depth (1, 4, 8, 16, 24, 32)
  unsigned int CompMethod;         // compression method being used (0, 1, 2, 3)
  unsigned int Size_of_Raw;        // size of the raw bitmap data
  signed int HRes;                 // horizontal resolution of the image. (pixel per meter, signed integer)
  signed int VRes;                 // vertical resolution of the image. (pixel per meter, signed integer)
  unsigned int Num_of_Col;         // number of colors in the color palette, or 0 to default to 2^n
  unsigned int Num_of_ICol;        // number of important colors used, or 0 when every color is important; generally ignored
};

struct ColorTable
{
    unsigned char data[1024];
};

struct Pixel
{
    unsigned char pix[262144];      
};

这是问题的更新相关代码:

//write pixel data to new file
    unsigned char p;
    for (int j = 0; j < H; j++)
    {
        for (int i = 0; i < W; i++)
        {
            p = opx.pix[j*W + i];
            outFile.write(reinterpret_cast<char*>(&p), sizeof(p));
        }
    }

这是输出到屏幕的内容:

 Bitmap File Header

 Header Field: BM
 Size of BMP: 263222
 Start Address: 1078

 Bitmap Information Header

 Header size: 40
 Image width: 512
 Image height: 512
 Number of bits for pixel: 8
 Used compression: 0
 Image size: 0
 Horizontal resolution: 2835
 Vertical resolution: 2835
 Number of colors in the color palette: 256
 Number of important colors used: 256
---------------------------------------------------

 Total number of bytes to store one row of pixels: 512

 Total amount of bytes to store the array of pixels: 262144

 The first three entries in color table: 0 0 0

 The first three pixels (Blue, Green, Red): 98 96 91

我使用的十六进制编辑器是 HxD。我使用的编译器是 Qt Creator。

这是我正在使用的 bmp 图片:https://drive.google.com/file/d/0B4emsCaxwnh5c3IxNWdsc1k2MGs/view?usp=sharing

感谢所有花费宝贵时间浏览这堵文字墙的人。我很感激反馈,如果我遗漏了一些明显的东西,一定要让我知道。

【问题讨论】:

  • 首先你在BMPFH* fh = (BMPFH*)(temp);处设置了严格的别名规则。只需读取结构整个结构而不是字节数组。
  • 会不会是您直接读取DIBH 结构,但一次写入一个元素,并且结构成员未对齐到单字节(#pragma pack)?
  • BMP文件也有不同的版本。
  • PPM 格式 en.wikipedia.org/wiki/Netpbm_format#PPM_example 在第一次尝试时更容易读/写。 bmp 包含一些您不想担心的奇怪问题。
  • inFile.seekg(57, ios::beg); 似乎很可疑,因为偏移量很奇怪。 .BMP 中的几乎所有内容都与至少一个偶数偏移对齐,通常与 4 的倍数对齐。

标签: c++ qt bitmap bmp ofstream


【解决方案1】:

您的最终嵌套循环(输出循环)一遍又一遍地写入同一行像素数据。

//write pixel data to new file
unsigned char p;
for (int j = 0; j < H; j++)
    {
        for (int i = 0; i < W; i++)
        {
            p = opx.pix[i];
            outFile.write(reinterpret_cast<char*>(&p), sizeof(p));
        }
    }

这一行中的i

            p = opx.pix[i];

是列偏移量。它从每一行重新开始。

要修复它,您可以将其更改为:

            p = opx.pix[j*W + i];

有更有效的方法可以做到这一点,但这会让您的代码正常工作。

十六进制编辑器中的 630 是文件开头的偏移量(以十六进制表示),您的问题似乎从那之后的六个字节开始。请注意,636h 将是第二行像素数据的第一个字节。 (文件头是14字节,DIB头是40字节,颜色表是1024字节,第一行是512字节。)这是寻找问题的线索。

【讨论】:

  • 非常感谢您的洞察力。我进行了更改,起初它导致程序冻结,但那是因为“unsigned char pix [512]”。我将其更改为 262144,程序输出与原始 bmp 文件完全匹配的内容。我选择 262144 是因为这是存储像素数组所需的字节数。那是放在那里的正确数字吗? (参考我代码中Pixel的struct)
  • 是的,这是适合此 .BMP 的大小。请注意,如果您尝试在不同格式的文件上使用它,可能会出现其他问题。 .BMP 格式有很多法律变体。
猜你喜欢
  • 2016-06-22
  • 2020-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-10
相关资源
最近更新 更多