[数据压缩]bmp序列转yuv文件

目录

bmp文件分析

bmp转yuv思路

代码实现

结果展示


bmp文件分析

  • bmp简介

BMP是英文Bitmap(位图)的简写,是Windows采用的图像文件存储格式。在Windows环境下运行的所有图像处理软件都支持这种格式。在Windows环境下运行的所有图像处理软件都支持这种格式。Windows 3.0以后的BMP文件都是指设备无关位图(DIB,device-independent bitmap)。BMP位图文件默认的文件扩展名是.BMP,有时它也会以.DIB或.RLE作扩展名。

  • bmp文件结构

BMP文件由4部分组成:

1.   位图文件头(bitmap-file header)

名称

占用空间

内容

bfType

2字节

标识,就是“BM”二字

bfSize

4字节

BMP文件的大小

bfReserved1/2

4字节

保留字

bfOffBits

4字节

偏移数,即 “位图文件头+位图信息头+调色板” 的大小

typedef struct tagBITMAPFILEHEADER {
    WORD bfType; /* 说明文件的类型 */
    DWORD bfSize; /* 说明文件的大小,用字节为单位 */
    WORD bfReserved1; /* 保留,设置为 0 */
    WORD bfReserved2; /* 保留,设置为 0 */
    DWORD bfOffBits; /* 说明从 BITMAPFILEHEADER 结构开始到实际的图像数 据之间的字节偏移量 */
} BITMAPFILEHEADER;

2.   位图信息头(bitmap-informationheader)

名称

占用空间

内容

biSize

4字节

位图信息头的大小

biWidth

4字节

位图的宽度(像素)

biHeight

4字节

位图的高度(像素)

biPlanes

2字节

固定值1

biBitCount

2字节

像素位数

(1-黑白图,4-16色,8-256色,24-真彩色)

biCompression

4字节

压缩方式

biSizeImage

4字节

位图全部像素占用的字节数

biXPelsPerMeter

4字节

水平分辨率(像素/米)

biYPelsPerMeter

4字节

垂直分辨率(像素/米)

biClrUsed

4字节

位图使用的颜色数

biClrImportant

4字节

重要的颜色数

typedef struct tagBITMAPINFOHEADER {
    DWORD biSize; /* 说明结构体所需字节数 */
    LONG biWidth; /* 以像素为单位说明图像的宽度 */
    LONG biHeight; /* 以像素为单位说明图像的高度 */
    WORD biPlanes; /* 说明位面数,必须为 1 */
    WORD biBitCount; /* 说明位数/像素,1、2、4、8、24 */
    DWORD biCompression; /* 说明图像是否压缩及压缩类型 BI_RGB,BI_RLE8,BI_RLE4,
BI_BITFIELDS */
    DWORD biSizeImage; /* 以字节为单位说明图像大小,必须是 4 的整数倍*/
    LONG biXPelsPerMeter; /*目标设备的水平分辨率,像素/米 */
    LONG biYPelsPerMeter; /*目标设备的垂直分辨率,像素/米 */
    DWORD biClrUsed; /* 说明图像实际用到的颜色数,如果为 0,则颜色数为 2 的 biBitCount次方 */
    DWORD biClrImportant; /*说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要。*/
} BITMAPINFOHEADER;

3.   颜色表(color table)

可选部分。

本次采用24位真彩色位图,没有颜色表。

typedef struct tagRGBQUAD {
    BYTE rgbBlue; /*指定蓝色分量*/
    BYTE rgbGreen; /*指定绿色分量*/
    BYTE rgbRed; /*指定红色分量*/
    BYTE rgbReserved; /*保留,指定为 0*/
} RGBQUAD;

4.   颜色点阵数据(bits data)

位图的像素部分,按照自下向上,自左向右的顺序排列的。

bmp转yuv思路


1. 读取BMP文件,提取BMP的文件头和信息头信息,用结构体File_header盛放文件头数据,用结构体Info_header盛放信息头数据

2.调整图片的尺寸,使图像的长是4的倍数,宽是2的倍数

3.提取BMP的有效数据,转换为RGB数据

4.进行RGB2YUV的转换

5.根据设置的帧数写YUV文件

代码实现

  • rgb转yuv实现部分
void InitLookupTable()
{
    int i;
    for (i = 0; i < 256; i++) RGBYUV02990[i] = (float)0.2990 * i;
    for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i;
    for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i;
    for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i;
    for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i;
    for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i;
    for (i = 0; i < 256; i++) RGBYUV00813[i] = (float)0.0813 * i;
}

int RGB2YUV (int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip)
{
    static int init_done = 0;

    long i, j, size;
    unsigned char *r, *g, *b;
    unsigned char *y, *u, *v;
    unsigned char *pu1, *pu2, *pv1, *pv2, *psu, *psv;
    unsigned char *y_buffer, *u_buffer, *v_buffer;
    unsigned char *sub_u_buf, *sub_v_buf;

    if (init_done == 0)
    {
        InitLookupTable();
        init_done = 1;
    }

    if ((x_dim % 2) || (y_dim % 2)) return 1;
    size = x_dim * y_dim;

    y_buffer = (unsigned char *)y_out;
    sub_u_buf = (unsigned char *)u_out;
    sub_v_buf = (unsigned char *)v_out;
    u_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));
    v_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));
    if (!(u_buffer && v_buffer))
    {
        if (u_buffer) free(u_buffer);
        if (v_buffer) free(v_buffer);
        return 2;
    }

    b = (unsigned char *)bmp;
    y = y_buffer;
    u = u_buffer;
    v = v_buffer;

    if (!flip) {
        for (j = 0; j < y_dim; j ++)
        {
            y = y_buffer + (y_dim - j - 1) * x_dim;
            u = u_buffer + (y_dim - j - 1) * x_dim;
            v = v_buffer + (y_dim - j - 1) * x_dim;

            for (i = 0; i < x_dim; i ++) {
                g = b + 1;
                r = b + 2;
                *y = (unsigned char)(  RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
                *u = (unsigned char)(- RGBYUV01684[*r] - RGBYUV03316[*g] + (*b)/2          + 128);
                *v = (unsigned char)(  (*r)/2          - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);
                b += 3;
                y ++;
                u ++;
                v ++;
            }
        }
    } else {
        for (i = 0; i < size; i++)
        {
            g = b + 1;
            r = b + 2;
            *y = (unsigned char)(  RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
            *u = (unsigned char)(- RGBYUV01684[*r] - RGBYUV03316[*g] + (*b)/2          + 128);
            *v = (unsigned char)(  (*r)/2          - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);
            b += 3;
            y ++;
            u ++;
            v ++;
        }
    }

    for (j = 0; j < y_dim/2; j ++)
    {
        psu = sub_u_buf + j * x_dim / 2;
        psv = sub_v_buf + j * x_dim / 2;
        pu1 = u_buffer + 2 * j * x_dim;
        pu2 = u_buffer + (2 * j + 1) * x_dim;
        pv1 = v_buffer + 2 * j * x_dim;
        pv2 = v_buffer + (2 * j + 1) * x_dim;
        for (i = 0; i < x_dim/2; i ++)
        {
            *psu = (*pu1 + *(pu1+1) + *pu2 + *(pu2+1)) / 4;
            *psv = (*pv1 + *(pv1+1) + *pv2 + *(pv2+1)) / 4;
            psu ++;
            psv ++;
            pu1 += 2;
            pu2 += 2;
            pv1 += 2;
            pv2 += 2;
        }
    }
    free(u_buffer);
    free(v_buffer);

    return 0;
}
  • main函数部分
int main(int argc, char* argv[])
{
    FILE *bmpfile = NULL;
    FILE *yuvfile = NULL;
    char* bmpFileName[5];
    bmpFileName[0] = argv[1];
    bmpFileName[1] = argv[2];
    bmpFileName[2] = argv[3];
    bmpFileName[3] = argv[4];
    bmpFileName[4] = argv[5];
    char* yuvFileName = NULL;
    yuvFileName = argv[6];
    int fnum;
    fnum = atoi(argv[7]);
    if (!(yuvfile=fopen(yuvFileName, "wb") ))
    {
        printf("输出yuv文件打开失败!\n");
    }
    BITMAPFILEHEADER File_header;
    BITMAPINFOHEADER Info_header;
    unsigned char *buffer = NULL,*ybuf=NULL,*ubuf=NULL,*vbuf=NULL;

    for(int i=0;i<5;i++)
    {
        if (!(bmpfile=fopen(bmpFileName[i], "rb")))
        {
            printf("输入bmp文件打开失败!\n");
        }
        if(fread(&File_header, sizeof(BITMAPFILEHEADER), 1, bmpfile) != 1)
        {
            cout<<("读取file_header失败")<

设置命令行参数

[数据压缩]bmp序列转yuv文件_第1张图片

结果展示

选取了5张bmp格式图片

[数据压缩]bmp序列转yuv文件_第2张图片

生成了共250帧的yuv文件

yuv文件播放

你可能感兴趣的:(数据压缩,c++,图像处理)