[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

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