本文介绍了将rgb视频图像封装为bmp图像的方法,附有详细的代码和图像示例。文中rgb24文件需要使用yuv/rgb播放器才能查看,参考播放器可选择雷神推荐的修改了一个YUV/RGB播放器,或者小编使用的vooya播放器。
bmp结构
bmp图片由文件头和像素两部分组成,其中文件头又包括位图文件信息和位图结构信息,文件头两部分信息的结构如下所示。
typedef struct tagBITMAPFILEHEADER
{
unsigned short int bfType; //位图文件的类型,必须为BM
unsigned long bfSize; //文件大小,以字节为单位
unsigned short int bfReserverd1; //位图文件保留字,必须为0
unsigned short int bfReserverd2; //位图文件保留字,必须为0
unsigned long bfbfOffBits; //位图文件头到数据的偏移量,以字节为单位
}BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER
{
long biSize; //该结构大小,字节为单位
long biWidth; //图形宽度以象素为单位
long biHeight; //图形高度以象素为单位
short int biPlanes; //目标设备的级别,必须为1
short int biBitcount; //颜色深度,每个象素所需要的位数
short int biCompression; //位图的压缩类型
long biSizeImage; //位图的大小,以字节为单位
long biXPelsPermeter; //位图水平分辨率,每米像素数
long biYPelsPermeter; //位图垂直分辨率,每米像素数
long biClrUsed; //位图实际使用的颜色表中的颜色数
long biClrImportant; //位图显示过程中重要的颜色数
}BITMAPINFOHEADER;
BMP采用的是小端(Little Endian)存储方式。这种存储方式中“RGB24”格式的像素的分量存储的先后顺序为B、G、R。由于RGB24格式存储的顺序是R、G、B,所以需要将“R”和“B”顺序作一个调换再进行存储。
函数代码
本函数实现了将rgb视频图像封装为bmp图像,具体代码如下所示。
int CTransPic::simplest_rgb24_to_bmp(const char*url, int w, int h, const char* bmppath)
{
typedef struct
{
long imageSize;
long black;
long startposion;
}BmpHead;
typedef struct
{
long Length;
long width;
long height;
unsigned short colorPlane;
unsigned short bitColor;
long zipFormat;
long realSize;
long xPels;
long yPels;
long colorUse;
long colorImportant;
}InfoHead;
BmpHead m_BmpHeader = { 0 };
InfoHead m_BmpInfoHeader = { 0 };
char bfType[2] = { 'B', 'M' };
int Head_Size = sizeof(InfoHead)+sizeof(BmpHead)+sizeof(bfType);
unsigned char* rgb24_buffer = NULL;
fstream fp_rgb24, fp_bmp;
fp_rgb24.open(url, ios::in | ios::binary);
fp_bmp.open(bmppath, ios::out | ios::binary);
rgb24_buffer = (unsigned char*)malloc(w*h * 3);
fp_rgb24.read((char*)rgb24_buffer, w*h * 3);
m_BmpHeader.imageSize = 3 * w*h + Head_Size;
m_BmpHeader.startposion = Head_Size;
m_BmpInfoHeader.Length = sizeof(InfoHead);
m_BmpInfoHeader.width = w;
//BMP storage pixel data in opposite direction of Y-axis (from bottom to top).
m_BmpInfoHeader.height = -h;
m_BmpInfoHeader.colorPlane = 1;
m_BmpInfoHeader.bitColor = 24;
m_BmpInfoHeader.realSize = 3 * w*h;
fp_bmp.write(bfType, sizeof(bfType));
fp_bmp.write((const char*)&m_BmpHeader, sizeof(m_BmpHeader));
fp_bmp.write((const char*)&m_BmpInfoHeader, sizeof(m_BmpInfoHeader));
//BMP save R1|G1|B1,R2|G2|B2 as B1|G1|R1,B2|G2|R2
//It saves pixel data in Little Endian
//So we change 'R' and 'B'
for (int j = 0; j < h; j++){
for (int i = 0; i < w; i++){
char temp = rgb24_buffer[(j*w + i) * 3 + 2];
rgb24_buffer[(j*w + i) * 3 + 2] = rgb24_buffer[(j*w + i) * 3 + 0];
rgb24_buffer[(j*w + i) * 3 + 0] = temp;
}
}
fp_bmp.write((const char*)rgb24_buffer, w*h * 3);
free(rgb24_buffer);
fp_bmp.close();
fp_rgb24.close();
return 0;
}
函数调用方法如下所示。
TranPic.simplest_rgb24_to_bmp("2_1000x667.rgb", 1000, 667, "output_bmp.bmp");
测试用例
程序测试用的原图如下所示:
测试输出bmp图像如下所示。
下载
vooya播放器:https://download.csdn.net/download/whegqing/11519824
测试用例图:https://download.csdn.net/download/whegqing/11520875
版本声明:本文参考了雷神的文章,文中代码重新做了编写,亲测可用,欢迎转载交