zoukankan      html  css  js  c++  java
  • 音视频入门-03-RGB转成BMP图片

    * 音视频入门文章目录 *

    BMP 文件格式解析

    BMP 文件由文件头、位图信息头、颜色信息和图形数据四部分组成。

    位图文件头(14个字节) 位图信息头(40个字节) 颜色信息 图形数据
    • 文件头与信息头一共是 54 字节
    • RGB 数据部分:
      RGB24 文件存储的顺序是 RGB, RGB, RGB ...... RGB
      BMP 文件 RGB 数据存储的顺序是 BGR, BGR, BGR ... BGR

    位图文件头

    位图文件头分 4 部分,共 14 字节

    名称 占用空间 内容 示例数据
    bfType 2字节 标识,就是“BM” BM
    bfSize 4字节 整个 BMP 文件的大小 0x000C0036(786486)
    bfReserved1 2字节 保留字 0
    bfReserved2 2字节 保留字 0
    bfOffBits 4字节 偏移数,即位图文件头+位图信息头+调色板的大小 0x36(54)

    位图信息头

    位图信息头共 40 字节

    名称 占用空间 内容 示例数据
    biSize 4字节 位图信息头的大小,为40 0x28(40)
    biWidth 4字节 位图的宽度,单位是像素 0x200(512)
    biHeight 4字节 位图的高度,单位是像素 0x200(512)
    biPlanes 2字节 固定值1 1
    biBitCount 2字节 每个像素的位数 1-黑白图,4-16色,8-256色,24-真彩色,32-带 alpha 通道 0x18(24)
    biCompression 4字节 压缩方式,BI_RGB(0)为不压缩 0
    biSizeImage 4字节 位图全部像素占用的字节数,BI_RGB时可设为0 0x0C
    biXPelsPerMeter 4字节 水平分辨率(像素/米) 0
    biYPelsPerMeter 4字节 垂直分辨率(像素/米) 0
    biClrUsed 4字节 位图使用的颜色数 如果为0,则颜色数为2的biBitCount次方 0
    biClrImportant 4字节 重要的颜色数,0代表所有颜色都重要 0

    将 RGB24 像素点数据转成 BMP 格式图片

    转换代码:

    #include <stdio.h>
    #include <stdlib.h>
    
    // 彩虹的七种颜色
    u_int32_t rainbowColors[] = {
            0XFF0000, // 红
            0XFFA500, // 橙
            0XFFFF00, // 黄
            0X00FF00, // 绿
            0X007FFF, // 青
            0X0000FF, // 蓝
            0X8B00FF  // 紫
    };
    
    /*bmp file header*/
    typedef struct {
        unsigned int   bfSize;           /* Size of file */
        unsigned short bfReserved1;      /* Reserved */
        unsigned short bfReserved2;      /* ... */
        unsigned int   bfOffBits;        /* Offset to bitmap data */
    } BitmapFileHeader;
    
    /*bmp info header*/
    typedef struct {
        unsigned int   biSize; /* Size of info header */
        int            biWidth; /* Width of image */
        int            biHeight; /* Height of image */
        unsigned short biPlanes; /* Number of color planes */
        unsigned short biBitCount; /* Number of bits per pixel */
        unsigned int   biCompression; /* Type of compression to use */
        unsigned int   biSizeImage; /* Size of image data */
        int            biXPelsPerMeter; /* X pixels per meter */
        int            biYPelsPerMeter; /* Y pixels per meter */
        unsigned int   biClrUsed; /* Number of colors used */
        unsigned int   biClrImportant; /* Number of important colors */
    } BitmapInfoHeader;
    
    void writeRGBToBmp(char *filename, int width, int height) {
        FILE *bitmapFile = fopen(filename, "wb");
        if(!bitmapFile) {
            printf("Could not write file 
    ");
            return;
        }
    
        uint16_t bfType = 0x4d42;
    
        BitmapFileHeader fileHeader;
        fileHeader.bfReserved1 = 0;
        fileHeader.bfReserved2 = 0;
        fileHeader.bfSize = 2 + sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader) + width*height*3;
        fileHeader.bfOffBits = 0x36;
    
        BitmapInfoHeader infoHeader;
        infoHeader.biSize = sizeof(BitmapInfoHeader);
        infoHeader.biWidth = width;
        infoHeader.biHeight = height;
        infoHeader.biPlanes = 1;
        infoHeader.biBitCount = 24;
        infoHeader.biSizeImage = 0;
        infoHeader.biCompression = 0;
        infoHeader.biXPelsPerMeter = 5000;
        infoHeader.biYPelsPerMeter = 5000;
        infoHeader.biClrUsed = 0;
        infoHeader.biClrImportant = 0;
    
        fwrite(&bfType, sizeof(bfType), 1, bitmapFile);
        fwrite(&fileHeader, sizeof(fileHeader), 1, bitmapFile);
        fwrite(&infoHeader, sizeof(infoHeader), 1, bitmapFile);
    
        // 写入图像数据
        for (int i = 0; i < width; ++i) {
    
            // 当前颜色
            u_int32_t currentColor = rainbowColors[0];
            if(i < 100) {
                currentColor = rainbowColors[0];
            } else if(i < 200) {
                currentColor = rainbowColors[1];
            } else if(i < 300) {
                currentColor = rainbowColors[2];
            } else if(i < 400) {
                currentColor = rainbowColors[3];
            } else if(i < 500) {
                currentColor = rainbowColors[4];
            } else if(i < 600) {
                currentColor = rainbowColors[5];
            } else if(i < 700) {
                currentColor = rainbowColors[6];
            }
            // 当前颜色 R 分量
            u_int8_t R = (currentColor & 0xFF0000) >> 16;
            // 当前颜色 G 分量
            u_int8_t G = (currentColor & 0x00FF00) >> 8;
            // 当前颜色 B 分量
            u_int8_t B = currentColor & 0x0000FF;
    
            for (int j = 0; j < height; ++j) {
                // 按 BGR 顺序写入一个像素 RGB24 到文件中
                fwrite(&B, 1, 1, bitmapFile);
                fwrite(&G, 1, 1, bitmapFile);
                fwrite(&R, 1, 1, bitmapFile);
            }
        }
    
        // 关闭文件
        fclose(bitmapFile);
    }
    
    int main() {
        writeRGBToBmp("/Users/staff/Desktop/rainbow-700x700.bmp", 700, 700);
        return 0;
    }
    

    检查生成的 BMP 图片

    Congratulations! 图片查看软件识别出我们的 BMP 图片了,预览正常!
    BUT!好像哪里不对劲?!我们的彩虹倒过来了!
    彩虹的颜色,从上到下应该是:
    红 -> 橙 -> 黄 -> 绿 -> 青 -> 蓝 -> 紫
    这张图是:
    紫 -> 蓝 -> 青 -> 绿 -> 黄 -> 橙 -> 红

    image-demo-rainbow-bmp-reverse

    处理图片倒立问题

    BitmapInfoHeader 中的 biHeight 字段,
    biHeight 为正,位图自底向顶扫描,
    biHeight 为负,位图自顶向底扫描。
    如果这个值的设置和原始位图文件扫描方式不符,则图像显示可能会颠倒。


    将上面的转换代码中,BitmapInfoHeader 部分:

    // infoHeader.biHeight = height;
    infoHeader.biHeight = -height;
    

    image-demo-rainbow-bmp

    Congratulations!

    成功用像素点拼出了一张 “真正” 的图片!


    代码:

    rgb-to-bmp

    参考资料:

    维基百科-BMP

    位图(bmp)文件格式分析

    RGB24转换成BMP图像

    关于RGB32和RGB24的区别

    non-dword-aligned-pixel-to-dword-aligned-bitmap

    generate-bmp-file-from-array-of-rgb-values

    内容有误?联系作者:

    联系作者


  • 相关阅读:
    《Geometric Deep Learning综述介绍》
    《和想象不太一样的'Graph Neural Network + Zero Shot'》
    《几何深度学习前沿》
    《【Paper Live】滴滴出行-探索资源约束的Contextual Bandits问题 & KDD Cup滴滴出行比赛解读>
    《PDP: 解决约束满足问题的神经网络架构 | 刘晶 | 集智俱乐部图网络论文读书会20190819》
    《NeuroSAT: Learning a SAT Solver from Single-Bit Supervision》
    《OR Talk NO.5 | Facebook 田渊栋:用深度(强化)学习为组合优化寻找更好的启发式搜索策略》
    《OR Talk NO.15 | 在业界实验室做AI设计师是一种什么体验?》
    超级跳马 —— 矩阵快速幂优化DP
    图SLAM:Noob的同时本地化和映射指南
  • 原文地址:https://www.cnblogs.com/binglingziyu/p/audio-video-basic-03-rgb-to-bmp.html
Copyright © 2011-2022 走看看