[Video and Audio Data Processing] RGB24格式像素数据封装为BMP图像

0. BMP格式重点介绍

0.1 BMP采用的是小端(Little Endian)存储方式

这种存储方式中“RGB24”格式的像素的分量存储的先后顺序为B、G、R。由于RGB24格式存储的顺序是R、G、B,所以需要将“R”和“B”顺序作一个调换再进行存储。

0.2 BMP图像的高度与RGB相反

0.3 BMP文件结构

BMP文件是由BITMAPFILEHEADER、BITMAPINFOHEADER、RGB像素数据共3个部分构成,它的结构如下图所示。

//BITMAPFILEHEADER

//BITMAPINFOHEADER

//RGB像素数据

//其中前两部分的结构如下所示。在写入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;

1. 代码如下

extern "C"
{
#ifdef __cplusplus
#define __STDC_CONSTANT_MACROS

#endif

}
extern "C" {

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
}



/**
 * Convert RGB24 file to BMP file
 * @param rgb24path    Location of input RGB file.
 * @param width        Width of input RGB file.
 * @param height       Height of input RGB file.
 * @param url_out      Location of Output BMP file.
 */
int simplest_rgb24_to_bmp(const char* rgb24path, int width, int height, 
const char* bmppath) {

	typedef struct { //tagBITMAPFILEHEADER关键结构
		long imageSize; //文件大小,已字节为单位
		long blank;
		long startPosition;
	}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;

	int i = 0, j = 0;
	BmpHead m_BMPHeader = { 0 };
	InfoHead  m_BMPInfoHeader = { 0 };
	char bfType[2] = { 'B','M' };
	int header_size = sizeof(bfType) + sizeof(BmpHead) + sizeof(InfoHead);

	unsigned char* rgb24_buffer = NULL;
	FILE* fp_rgb24 = NULL, * fp_bmp = NULL;

	if ((fp_rgb24 = fopen(rgb24path, "rb")) == NULL) { //输入文件
		printf("Error: Cannot open input RGB24 file.\n");
		return -1;
	}
	if ((fp_bmp = fopen(bmppath, "wb")) == NULL) { //bmppath为生成文件
		printf("Error: Cannot open output BMP file.\n");
		return -1;
	}

	rgb24_buffer = (unsigned char*)malloc(width * height * 3); 
	//申请内存空间,大小由BMP图像类型决定
	fread(rgb24_buffer, 1, width * height * 3, fp_rgb24); 
	//一个字节一个字节的把fp_rgb24里面的数据存到rgb24_buffer里面

	m_BMPHeader.imageSize = 3 * width * height + header_size;
	//文件大小,总的存储RGB数据的加上文件头
	
	m_BMPHeader.startPosition = header_size;//位图文件头到数据的偏移量,以字节为单位

	m_BMPInfoHeader.Length = sizeof(InfoHead); //改结构的大小
	m_BMPInfoHeader.width = width;//BMP图像宽度以为RGB像素的宽度
	//BMP storage pixel data in opposite direction of Y-axis (from bottom to top).
	m_BMPInfoHeader.height = -height;//BMP图像高度和原RGB是相反的
	m_BMPInfoHeader.colorPlane = 1; //目标设备的级别,必须为1
	m_BMPInfoHeader.bitColor = 24;//颜色深度,每个像素所需要的位数
	m_BMPInfoHeader.realSize = 3 * width * height;//位图的大小

	fwrite(bfType, 1, sizeof(bfType), fp_bmp);//把bfType对应的BM写入fp_bmp中
	fwrite(&m_BMPHeader, 1, sizeof(m_BMPHeader), fp_bmp);
	//继续上面的文件指针,m_BMPHeader写入fp_bmp中
	
	fwrite(&m_BMPInfoHeader, 1, sizeof(m_BMPInfoHeader), fp_bmp);
	//继续上面的文件指针,m_BMPInfoHeader写入fp_bmp中

	//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 (j = 0; j < height; j++) {
		for (i = 0; i < width; i++) {
			char temp = rgb24_buffer[(j * width + i) * 3 + 2];
			rgb24_buffer[(j * width + i) * 3 + 2] = rgb24_buffer[(j * width + i) * 3 + 0];
			rgb24_buffer[(j * width + i) * 3 + 0] = temp;
			//将RGB数据中每个像素的“R”和“B”的位置互换。
		}
	}
	fwrite(rgb24_buffer, 3 * width * height, 1, fp_bmp);
	//继续上面的文件指针,把交换过的RGB数据存到fp_bmp
	fclose(fp_rgb24);//关闭流
	fclose(fp_bmp);//关闭流
	free(rgb24_buffer);//释放内存
	printf("Finish generate %s!\n", bmppath);
	return 0;
}




int main()
{
	simplest_rgb24_to_bmp("lena_256x256_rgb24.rgb", 256, 256, "output_lena.bmp");
    return 0;
}

2. 效果

下图为输入: RGB24格式的图像lena_256x256_rgb24.rgb

在这里插入图片描述

下图是封装为BMP格式后的图像output_lena.bmp,封装后的图像使用普通的看图软件就可以查看。

在这里插入图片描述

在这里插入图片描述
用Windows照片查看器打开,效果如下:

在这里插入图片描述

参考链接:https://blog.csdn.net/leixiaohua1020/article/details/50534150

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章