实验二 BMP2YUV文件转换
来源:互联网 发布:c语言memset头文件 编辑:程序博客网 时间:2024/05/17 08:10
一、实验原理
研究各种图像文件格式之间的转换,主要可以从两方面入手:1.从其中一种文件格式出发,考虑图像数据在该种文件格式下的内部存储方式。如:图像数据采用的色彩空间是什么?它存储在文件数据流的哪个部分?该格式除了实际的图像数据,是否还有其它信息数据?它们又存储在哪里?2.寻找两种文件格式之间的关系,以及它们之间的转换方法。关系如文件格式之间组织结构的异同,转换方法取决于色彩空间之间的转换公式。
从上述两方面来分析比较本次实验待转换的两种文件格式——bmp、yuv。
bmp
bmp(全称Bitmap)是Windows操作系统中的标准图像文件格式。BMP文件的图像深度可选1bit、4bit、8bit、16bit及24bit。典型的BMP图像文件由四部分组成:
(1)位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息;
(2)位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息;在转换成yuv时,bmp图像的宽、高需为4的倍数。
(3)调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;
(4)位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在 24 位图中直接使用RGB,而其他的小于 24 位的使用调色板中颜色索引值。bmp的实际图像数据是以自下而上、自左向右的扫描方式存放的。
以一幅24bit的bmp(无调色板)为例,以二进制方式打开它,观察内部数据结构:
图中以不同颜色标示出了文件头和信息头部分,以及其中包含的几个重要的数据。注意计算机为小端系统,有先进后出的准则,在读取时要注意顺序。如图中图像的宽应读作(000002A8)B=680。
以下给出bmp的文件头、信息头、调色板中应包含的所有数据(已包含在windows.h库里,实际操作时要记得包含该库):
typedef struct tagBITMAPFILEHEADER { WORD bfType; /* 说明文件的类型 */ DWORD bfSi; /* 说明文件的大小,用字节为单位 */ WORD bfReserved1; /* 保留,设置为0 */ WORD bfReserved2; /* 保留,设置为0 */ DWORD bfOffBits; /* 说明从BITMAPFILEHEADER结 构开始到实际的图像数据之间的字节偏移量 */} BITMAPFILEHEADER; /* 文件头 */
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; /* 信息头 */
typedef struct tagRGBQUAD { BYTE rgbBlue; /*指定蓝色分量*/ BYTE rgbGreen; /*指定绿色分量*/ BYTE rgbRed; /*指定红色分量*/ BYTE rgbReserved; /*保留,指定为0*/} RGBQUAD; /* 调色板 */
- yuv
yuv是一种简单粗暴的格式,它不像bmp需要诸多相关信息放在文件里给定义,就直接叭叭叭的yyyyuuvv……写下去了。有关yuv格式的其它内容(与RGB的转换、采样等)已在实验一中有所体现,在此不再赘述。
二、流程分析
1.bmp2yuv(24bit无调色板)的工程除头文件外共包含了三个cpp文件:main.cpp、bmp2yuv.cpp、rgb2yuv.cpp(实验一中的文件直接调用即可)。
2.writeYUVvideo。完成bmp到yuv图片的转换后,再依次抽取这些yuv数据写入一个新的yuv数据流中,可以实现将生成的yuv图片拼接成一个200帧的yuv视频文件。
三、关键代码及其分析
main.cpp
#include <stdio.h>#include <stdlib.h>#include <malloc.h>#include <windows.h> #include <math.h>#include "bmp2yuv.h"#define u_int8_t unsigned __int8#define u_int unsigned __int32#define u_int32_t unsigned __int32int main(int argc, char** argv){ unsigned int i; char* bmpFileName = NULL; char* yuvFileName = NULL; FILE *bmpFile = NULL; FILE *yuvFile = NULL; u_int8_t* bmpBuf = NULL; u_int8_t* yBuf = NULL; u_int8_t* uBuf = NULL; u_int8_t* vBuf = NULL; BITMAPFILEHEADER File_header;//文件头 BITMAPINFOHEADER Info_header;//信息头 //初始化 bmpFileName = argv[1]; yuvFileName = argv[2]; bmpFile = fopen(bmpFileName, "rb"); if (bmpFile == NULL) { printf("cannot find bmp file\n"); exit(1); } else { printf("The input bmp file is %s\n", bmpFileName); } yuvFile = fopen(yuvFileName, "wb"); if (yuvFile == NULL) { printf("cannot find yuv file\n"); exit(1); } else { printf("The output yuv file is %s\n", yuvFileName); } // read file & info header if(fread(&File_header,sizeof(BITMAPFILEHEADER),1,bmpFile) != 1) { printf("read file header error!"); exit(0); } if (File_header.bfType != 0x4D42)//4D42='BM' { printf("Not bmp file!"); exit(0); } else { //printf("this is a %s\n",itoa(File_header.bfType)); } if(fread(&Info_header,sizeof(BITMAPINFOHEADER),1,bmpFile) != 1) { printf("read info header error!"); exit(0); } // end read header //24bit暂不用调色板 /*RGBQUAD *pRGB = (RGBQUAD *)malloc(sizeof(RGBQUAD)*(unsigned char)pow(2,Info_header.biBitCount)); if(!MakePalette(pFile,file_h,info_h,pRGB)) printf("No palette!");*/ //开辟缓冲区 bmpBuf=(unsigned char *)malloc(Info_header.biWidth*Info_header.biHeight*3); yBuf=(unsigned char *)malloc(Info_header.biWidth*Info_header.biHeight); uBuf=(unsigned char *)malloc(Info_header.biWidth*Info_header.biHeight/4); vBuf=(unsigned char *)malloc(Info_header.biWidth*Info_header.biHeight/4); //读取bmp数据,调用bmp2yuv函数进行转换 while(fread(bmpBuf,Info_header.biWidth*Info_header.biHeight*3,1,bmpFile)) { if(BMP2YUV(bmpBuf,Info_header.biWidth,Info_header.biHeight, yBuf, uBuf, vBuf)) { printf("error"); return 0; } for (i = 0; i < Info_header.biWidth*Info_header.biHeight; i++) { if (yBuf[i] < 16) yBuf[i] = 16; if (yBuf[i] > 235) yBuf[i] = 235; } for (i = 0; i < Info_header.biWidth*Info_header.biHeight/4; i++) { if (uBuf[i] < 16) uBuf[i] = 16; if (uBuf[i] > 240) uBuf[i] = 240; if (vBuf[i] < 16) vBuf[i] = 16; if (vBuf[i] > 240) vBuf[i] = 240; } //写入yuv数据 fwrite(yBuf, 1, Info_header.biHeight * Info_header.biWidth, yuvFile); fwrite(uBuf, 1, (Info_header.biHeight * Info_header.biWidth) / 4, yuvFile); fwrite(vBuf, 1, (Info_header.biHeight * Info_header.biWidth) / 4, yuvFile); } /* cleanup */ free(bmpBuf); free(yBuf); free(vBuf); free(uBuf); fclose(bmpFile); fclose(yuvFile); return 0;}
bmp2yuv.cpp
#include <stdlib.h>#include <windows.h> #include "bmp2yuv.h"int BMP2YUV (void *bmp,long width,long height, void *y_out, void *u_out, void *v_out){ //由于24bit的bmp没有调色板,所以从main函数传递进来的*bmp里就是bgr数据,直接调用rgb2yuv函数即可 RGB2YUV(width,height,bmp,y_out,u_out,v_out,0); return 0;}
writeYUVvideo.cpp
#include <stdio.h>#include <stdlib.h>#include <malloc.h> #define u_int8_t unsigned __int8int main(int argc, char** argv){ int i,j,k; int width,height,n; char* inFileName = NULL; char* outFileName = NULL; FILE *inFile = NULL; FILE *outFile = NULL; u_int8_t* outBuf = NULL; u_int8_t* inBuf = NULL; /*通过命令行传入的参数依次为:宽、高、yuv1、yuv1所占帧数、yuv2、yuv2所占帧数、……、yuv5、yuv5所占帧数、输出yuv*/ width = atoi(argv[1]); height = atoi(argv[2]); outFileName=argv[13]; outFile = fopen(outFileName, "wb"); if (outFile == NULL) { printf("cannot find yuv file\n"); exit(1); } else { printf("The output yuv file is %s\n", outFileName); } /*开辟缓冲区*/ inBuf=(unsigned char *)malloc(width*height*3/2); outBuf=(unsigned char *)malloc(200*width*height*3/2); unsigned char *out;/*out指针指向当前操作的outBuf内容*/ for(i=0;i<10;i+=2) { /*循环读入输入的yuv文件及其帧数*/ inFileName=argv[i+3]; n=atoi(argv[i+4]); inFile = fopen(inFileName, "rb"); if (inFile == NULL) { printf("cannot find yuv file\n"); exit(1); } else { printf("The input yuv file is %s\n", inFileName); } fread(inBuf,width*height*3/2,1,inFile); for(j=0;j<n;j++) { out=outBuf+i*n*width*height*3/2/2+j*width*height*3/2;/*out的偏移量为之前所有的yuv所占帧的数据长度+当前yuv已写入的数据长度*/ for(k=0;k<width*height*3/2;k++) { *out=*(inBuf+k); out++; } } } fwrite(outBuf, 1, 200*width*height*3/2, outFile); /* cleanup */ fclose(inFile); fclose(outFile); free(inBuf); free(outBuf); return 0;}
四、实验结论
- 对比同一幅图像在宽、高不同(一幅的宽、高都是4的倍数,另一幅的都不是)时的转换结果
可见若bmp的宽、高不是4的倍数,转换后的yuv图像会有变形错位。 - 将5幅bmp图先转换成yuv,再通过writeYUVvideo完成图像流到视频流的写入。
随机截取生成的yuv视频流中的五幅图像:
- 实验二 BMP2YUV文件转换
- 数据压缩实验二:BMP2YUV文件转换
- bmp2yuv文件转换实验
- 【数据压缩】实验二 BMP2YUV
- 数据压缩实验二:bmp2yuv
- 实验二:BMP2YUV
- 实验二:BMP2YUV
- 《数据压缩》实验报告二·BMP2YUV实验
- 【数据压缩】BMP2YUV实验报告
- BMP2YUV实验报告
- BMP2YUV实验报告
- 数据压缩原理与应用 图像文件的读写和转换(BMP2YUV)实验报告
- bmp2yuv
- bmp2yuv
- bmp2yuv
- 实验二:大小写的转换
- 实验二:大小写的转换
- 【实验二】图像文件的读写和转换
- onsubmit用来表单的提交
- 关于字节对齐
- Zookeeper集群环境搭建
- 第39级台阶,简单DFS
- 分类算法-贝叶斯网络
- 实验二 BMP2YUV文件转换
- LeetCode Algorithms 292. Nim Game 题解
- mongoc_client_command_simple
- PowerDesigner连接oracle数据库 以及连接数据库时出现的问题
- 随记
- poj 3660
- nbut 1674
- c:求1-1000 以内的所有完数
- 算法提高 最长单词&&单词个数统计&&不同单词个数统计