一、实验要求
1、解析BMP格式文件,获取图像信息
2、转化BMP图像为YUV格式的图像
3、多张BMP图像,转化为YUV视频
二、实验内容
1.获取图片
获取(540*720)的bmp图片若干:
2.bmp格式基础
实验使用的是24位真彩色bmp文件。文件分为三个部分:
- FileHeader
- InfoHeader
- 图片RGB信息
使用#include<windows.h>
可以方便地将文件头信息读入结构体
3.编程实现
程序由【实验一】中rgb转yuv的代码修改而来。
主函数
主函数实现以下过程:
- 读参数中的bmp文件,获取宽高,色彩信息
- rgb转yuv
- 从第二张图片开始写入转场
- 写静态图片
- 将当前图片存入temp中,留给下一张转场用
代码如下
int main(int argc, char** argv)
{
u_int8_t* y_temp;
u_int8_t* u_temp;
u_int8_t* v_temp;
int transFrames = 30;//转场帧数
int photoFrames = 30;//静止图片帧数
for (int pic = 2; pic < argc; pic++) //从第二个参数到最后一个是图片
{
//1.读bmp文件头,获取宽高
BITMAPFILEHEADER File_header;
BITMAPINFOHEADER Info_header;
FILE* bmpFile;
bmpFile = fopen(argv[pic], "rb");
fread(&File_header, sizeof(BITMAPFILEHEADER), 1, bmpFile);
fread(&Info_header, sizeof(BITMAPINFOHEADER), 1, bmpFile);
u_int frameWidth;
u_int frameHeight;
frameWidth = Info_header.biWidth;
frameHeight = Info_header.biHeight;
//2.色彩信息读入rgb_buffer
u_int8_t* rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3);
fread(rgbBuf, 1, frameWidth * frameHeight * 3, bmpFile);
fclose(bmpFile);
//3.追加模式打开yuv文件
FILE* yuvFile = fopen(argv[1], "ab+");
//4.rgb转yuv
u_int8_t* yBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
u_int8_t* uBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);
u_int8_t* vBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);
if (RGB2YUV(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf, FALSE))
{
printf("error");
return 0;
}
for (int i = 0; i < frameWidth * frameHeight; i++)
{
if (yBuf[i] < 16) yBuf[i] = 16;
if (yBuf[i] > 235) yBuf[i] = 235;
}
for (int i = 0; i < frameWidth * frameHeight / 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;
}
//5.从第二张图片开始加入转场
if (pic > 2) {
for (int frame = 0; frame < transFrames; frame++) {
u_int8_t* y_mix = getInsertFrames(y_temp, yBuf, transFrames, frame, frameWidth, frameHeight);
u_int8_t* u_mix = getInsertFrames(u_temp, uBuf, transFrames, frame, frameWidth / 2, frameHeight / 2);
u_int8_t* v_mix = getInsertFrames(v_temp, vBuf, transFrames, frame, frameWidth / 2, frameHeight / 2);
fwrite(y_mix, 1, frameWidth * frameHeight, yuvFile);
fwrite(u_mix, 1, (frameWidth * frameHeight) / 4, yuvFile);
fwrite(v_mix, 1, (frameWidth * frameHeight) / 4, yuvFile);
}
}
//6.写静态图片
for (int frame = 0; frame < photoFrames; frame++) {
fwrite(yBuf, 1, frameWidth * frameHeight, yuvFile);
fwrite(uBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
fwrite(vBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
}
printf("\n%u %ux%u video frames written\n",
pic, frameWidth, frameHeight);
fclose(yuvFile);
//7.将当前图片存入temp中,留给下一张转场用
y_temp = (u_int8_t*)malloc(frameWidth * frameHeight);
u_temp = (u_int8_t*)malloc(frameWidth * frameHeight*0.5);
v_temp = (u_int8_t*)malloc(frameWidth * frameHeight*0.5);
for (int i = 0; i < frameWidth * frameHeight; i++)
{
*(y_temp + i) = *(yBuf + i);
}
for (int i = 0; i < frameWidth * frameHeight/4; i++)
{
*(u_temp + i) = *(uBuf + i);
*(v_temp + i) = *(vBuf + i);
}
}
return(0);
}
其中,RGB2YUV()
函数就是【实验一】中老师给的代码,所以不贴出。
调试参数
将需要生成的yuv文件名和bmp文件名作为参数进行输入:
转场函数 getInsertFrames()
getInsertFrames()
函数用来获得两张图片的混合帧,写了两种转场方式:叠加和划像
叠加:
u_int8_t* getInsertFrames_mix(u_int8_t* buf1, u_int8_t* buf2, int frame,int currentFrame, u_int frameWidth,u_int frameHeight) {
//获取两帧混合(插值)
//frame:总转场帧数
//currentFrame:当前帧
u_int8_t * mix = (u_int8_t*)malloc(frameWidth * frameHeight);
for (int j = 0; j < frameHeight * frameWidth; j++) {
*(mix + j) = int((*(buf2 + j)* currentFrame + *(buf1 + j)*(frame- currentFrame)) / frame);
}
return mix;
}
划像
u_int8_t* getInsertFrames_sweap(u_int8_t* buf1, u_int8_t* buf2, int frame, int currentFrame, u_int frameWidth, u_int frameHeight) {
//获取两帧混合(扫下来)
//frame:总转场帧数
//currentFrame:当前帧
u_int8_t * mix = (u_int8_t*)malloc(frameWidth * frameHeight);
for (int h = 0; h < frameHeight; h++) {
for (int w = 0; w < frameWidth; w++) {
if (currentFrame * frameHeight / frame > h) {
*(mix + h * frameWidth + w) = *(buf2 + h * frameWidth + w);
}
else {
*(mix + h * frameWidth + w) = *(buf1 + h * frameWidth + w);
}
}
}
return mix;
}
三、实验结果
实验结果使用LICEcap
软件录制GIF图片,csdn只能支持不超过5M图片,因此只录了一次图片切换。
(1)叠加
(2)划像
四、实验总结:
- C语言的结构体很方便快速读取文件的各部分信息
- 对于yuv视频,没有任何压缩非常占空间,冗余度非常高