BMP 序列转 YUV 文件
1.实现思路
工具:c语言
整体思路
1。打开并读入BMP文件、定义变量,开辟存储空间。BMP文件中首先被读入的应该是文件头和信息头,读入之后才能根据其中给出的关于位图的宽高、bit数等信息进行开辟空间等操作。在本实验中,定义两个指针:BITMAPFILEHEADER File_header; BITMAPINFOHEADER Info_header; 分别用来获取文件头和信息头的数据。注意,这两种类型需要加<windows.h>头文件。
2.提取出RGB数据,写入缓冲区。不同bit的文件不同处理。24bit图可以直接取图片数据;16bit比较复杂,需要取像素数据转换成8bit彩色分量后再写入rgbBuf;8bit,4bit,1bit均需要构造调色板。需要注意的是图像数据需要倒置。
3.调用“RGB2YUV.h”函数实现转换,并写入新的YUV文件。生成视频时可以循环写入,每张图片素材30帧。打开方式“wb+”可以下次继续写入。
4.释放缓冲区,关闭文件。
bmp2rgb
1.读取BMP文件,得到RGB数据:判断是否为BMP文件;判断文件是否可读出;要保证BMP图像的长必须是4的倍数,宽必须是2的倍数
2.通过信息头得到有效位图数据在BMP图像中的位置,进而对有效数据进行读取
3.BMP规定:位图数据自左向右、自下向上依次存放。因此注意。Index_Data是直接从BMP文件中读取的数据倒序存放的buffer,需要变为正序的,即Data
4.得到的Data并不一定是RGB数据,因为BMP有位深的类别。24位BMP,位图有效数据就是RGB,而16位、8位、4位、2位、1位的BMP则需要位操作,从DATA数据中“解析”出RGB数据,具体方法见下图与注释
rgb2yuv
公式:
Y=0.2990R+0.5870G+0.1140B
R-Y=0.7010R-0.5870G-0.1140B
B-Y=-0.2990R-0.5870G+0.8860B
U=-0.1684R-0.3316G+0.5B
V=0.5R-0.4187G-0.0813B
2.实验内容
程序实现
bmp2yuv.h
#ifndef BMP2YUV_H_
#define BMP2YUV_H_
//定义掩码组
typedef struct bit32Mask
{
unsigned int rgbRed;
unsigned int rgbGreen;
unsigned int rgbBlue;
unsigned int reserved;
}Mas32;
typedef struct bit16Mask
{
unsigned int rgbRed;
unsigned int rgbGreen;
unsigned int rgbBlue;
}Mas16;
int BMP2RGB32bit(int bitcount, int x_dim, int y_dim, void* bmpbuf, void* rgbbuf, void* mask);
int BMP2RGB24bit(int bitcount, int x_dim, int y_dim, void* bmpbuf, void* rgbbuf);
int BMP2RGB16bit(int bitcount, int x_dim, int y_dim, void* bmpbuf, void* rgbbuf, void* mask);
int BMP2RGBNOT24bit(int bitcount, int x_dim, int y_dim, void* bmpbuf, void* rgbbuf, void* pRGB);
int RGB2YUV(int x_dim, int y_dim, void* bmp, void* y_out, void* u_out, void* v_out, int flip);
void InitLookupTable();
void adjust(unsigned char* b, unsigned char* g, unsigned char* r, unsigned char* y, unsigned char* u, unsigned char* v);
#endif
rgb2yuv.h
#include "stdlib.h"
#include "bmp2yuv.h"
static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
static float RGBYUV01684[256], RGBYUV03316[256];
static float RGBYUV04187[256], RGBYUV00813[256];
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;
}
// 检查x_dim 和 y_dim 是否可被2整除
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;
//将RGB转为YUV
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;
adjust(b, g, r, y, u, v);
b += 3;
y++;
u++;
v++;
}
}
}
else {
for (i = 0; i < size; i++)
{
g = b + 1;
r = b + 2;
adjust(b, g, r, y, u, v);
b += 3;
y++;
u++;
v++;
}
}
// 对 UV 二次抽样
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