merlinzjl

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

Bmp图像的数据格式及读取

数据格式参考:https://www.cnblogs.com/l2rf/p/5643352.html

一、BMP文件读取

下面代码通过读取一个二值bmp文件,并将数据以01的形式打印到文件中,代码中对分配的内存没有手动释放。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
union MyByte
{
    byte bvalue;
    struct mytype
    {
    byte bit0 : 1;
    byte bit1 : 1;
    byte bit2 : 1;
    byte bit3 : 1;
    byte bit4 : 1;
    byte bit5 : 1;
    byte bit6 : 1;
    byte bit7 : 1;
    } type;
 
};
 
int main(void)
{
    //BMP文件的数据按照从文件头开始的先后顺序分为四个部分:
    //BITMAPFILEHEADER,位图文件头(bmp file header):  提供文件的格式、大小等信息
    //BITMAPINFOHEADER,位图信息头(bitmap information):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息
    //RGBQUAD,调色板(color palette):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表
    //位图数据(bitmap data):图像数据区
    MyByte my;
    my.bvalue = 0xF1;
    my.type.bit1;
    fstream fs;
    string path = "tmp.bmp";
    fs.open(path, ios::in | ios::binary);
    if (!fs.is_open())
    {
             return -1;
    }
 
    BITMAPFILEHEADER bmpFileHeader = { 0 };
    //读取header
    //sizeof(BITMAPFILEHEADER)在当前PC上大小为14,而不是16,如果是16需要注意对齐问题
    fs.read((char *)&bmpFileHeader, sizeof(BITMAPFILEHEADER));
    //文件标识符,必须为"BM",小端模式,即0x4d42 才是Windows位图文件
    if (bmpFileHeader.bfType != 0x4D42)
    {
        return -1;
    };
 
    BITMAPINFOHEADER bmpInfoHeader = { 0 };
    fs.read((char *)&bmpInfoHeader, sizeof(BITMAPINFOHEADER));
  
    if (bmpInfoHeader.biBitCount == 1)
    {  
        /*解析二值图像的调色板*/
        /*二值图像的调色板只有黑白两种颜色,即这边的pRGB只有两个元素,(0,0,0,0)和(255,255,255,0)*/
        /*第四个值保留,一般用于阿尔法通道*/<br>                /*biBitCount 小于等于8的情况下,都存有调色板,数据区对应的存储在调色板中的索引值,超过8时,bmp中不存储调色板信息*/
        int size = 1 << bmpInfoHeader.biBitCount;
        RGBQUAD *pRGB = new RGBQUAD[size];
 
        for (int i = 0; i < size; ++i)
        {
            fs.read((char *)&pRGB[i], sizeof(RGBQUAD));
        }
     
 
        /*计算每行读取的字节数。每行数据4字节对齐,不足4字节的会自动补齐*/
        int lineBytes = ((bmpInfoHeader.biWidth * bmpInfoHeader.biBitCount + 31) / 8) / 4 * 4;
        std::fstream fsout;
        vector<byte *> v;
        for (int j = 0; j < bmpInfoHeader.biHeight ; ++j)
        {
            byte *buf = new byte[lineBytes];
            memset(buf, 0, lineBytes);
            fs.read((char*)buf, lineBytes);
            v.push_back(buf);
        }
 
        fsout.open("t1022.txt", ios::out);
        //默认bmp位图数据存储是相反的,即上面的图像数据存储在数据末端。
        //读取时需要颠倒下。
        for (int j = bmpInfoHeader.biHeight - 1; j >= 0; --j)
        {
            byte * buf = v.at(j);
            for (int jj = 0; jj < lineBytes; ++jj)
            {
                MyByte b;
                b.bvalue = buf[jj];
                //注意字节序,前面的数据存储在高bit位。每比特存储的实质是调色板的索引值,即0表示pRGB[0]的值,这里表示(0,0,0)即黑色
                fsout << (unsigned int)b.type.bit7;
                fsout << (unsigned int)b.type.bit6;
                fsout << (unsigned int)b.type.bit5;
                fsout << (unsigned int)b.type.bit4;
                fsout << (unsigned int)b.type.bit3;
                fsout << (unsigned int)b.type.bit2;
                fsout << (unsigned int)b.type.bit1;
                fsout << (unsigned int)b.type.bit0;
            }
            fsout << endl;
        }
        fsout.close();
    }
 
    fs.close();
 
    return  0;
}

  截图如下:

 

原图:

 

 

 

posted on   merlinzjl  阅读(4126)  评论(0编辑  收藏  举报

编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示