简介
RGB文件
RGB文件是原始的没有压缩的包含红绿蓝三种颜色的图像文件。
常见的RGB格式例如RGB24,也就是一组RGB像素中的R、G、B各占8比特,即一个字节,一组RGB一共是24个比特。
这里只以RGB24为例。
YUV文件
YUV文件是与RGB文件同样属于原始的没有压缩的图像文件,只是YUV格式存储的是亮度Y、色差信号U和V。
和YUV不同的是,由大面积着色原理,人眼对于亮度信号的敏感度远强于颜色信号的敏感度。因此色度信号可以比亮度信号取得更少,而视觉上差别不大。
因此YUV又有多种取样结构,如4:4:4、4:2:2、4:2:0等。
显然4:4:4的画面质量最好。数字演播室采用的取样结构为4:2:2。
RGB与YUV的转换公式如下:
Y = 0.299 R + 0.587 G + 0.114 B R − Y = 0.701 R − 0.587 G − 0.114 B B − Y = − 0.299 R − 0.587 G + 0.886 B U = 0.713 ∗ ( R − Y ) + 128 V = 0.713 ∗ ( B − Y ) + 128 Y = 0.299R + 0.587G + 0.114B\\ R-Y = 0.701R - 0.587G-0.114B\\ B-Y = -0.299R - 0.587G + 0.886B\\\\ U = 0.713 *(R-Y) + 128\\ V = 0.713 * (B-Y) + 128 Y=0.299R+0.587G+0.114BR−Y=0.701R−0.587G−0.114BB−Y=−0.299R−0.587G+0.886BU=0.713∗(R−Y)+128V=0.713∗(B−Y)+128
YUV的Y、U、V的信号在YUV格式中是分开存放的。
BMP文件
BMP文件有两种颜色表示方式
- 24bit以下,带调色板的图像,从调色板里选取颜色
- 24bitRGB图像
这里只考虑后者,以后有时间的话会同时实现。
BMP文件有文件头,带有图片的一些元信息,如图片大小、长宽、调色版数量等等。
BMP开头是一个两字节的标识(Signature)“BM"。
接下来是文件头信息,带有文件基本的信息:文件大小和像素数据开始位置:
typedef struct
{
Char Signature[2];
DWORD FileSize;
DWORD _reserved;
DWORD DataOffset;
} BITMAPFILEHEADER;
("BM"标识也应该是BITMAPFILEHEADER的一部分,但是这样声明结构体,在C语言下会引起内存对齐的问题,不方便直接把文件头读进结构体,因此实际编码的时候没有把它放进结构体)
再接下来是文件信息头,包含了图片的元数据信息。
typedef struct
{
DWORD Size;
int Width;
int Height;
WORD Planes;
WORD BitCount;
DWORD Compression;
DWORD ImageSize;
DWORD XpixelsPerM;
DWORD YpixelsPerM;
DWORD CorlorsUsed;
DWORD ColorsImaportant;
} BITMAPINFOHEADER;
对于24bit像素的Bitmap文件,像素以RGB的形式直接存放在文件信息头之后,也就是BITMAPFILEHEADER的DataOffset指示的地方。
需要注意的是,BMP像素排列有两种方式,
- 从左上开始,从上到下
- 从左下开始,从下到上
判断方法是根据BITMAPINFOHEADER中Height的正负,当Height为正时,从上到下扫描,当Height为负时,从下到上扫描。
因此Height在结构体里应该声明成有符号整型。
实验内容
思路很简单,首先,无论输入的是什么格式,都一律解码为RGB格式。
RGB格式的数据进行转码比YUV格式更方便。
不同BMP的大小可能不一,因此在转换成YUV前需要根据输出尺寸进行裁剪。
在最终输出阶段,全部转换成YUV格式,然后按照要求的帧数重复写入到文件。
代码分析
一些定义
这些定义是放在头文件里的
typedef unsigned char BYTE;
typedef unsigned int DWORD;
typedef unsigned short WORD;
#ifndef _YUV_H_
#define _YUV_H_
typedef struct {
BYTE Y;
BYTE U;
BYTE V;
} YUV;
typedef struct {
BYTE R;
BYTE G;
BYTE B;
} RGB;
typedef struct {
int Y;
int U;
int V;
}YUV_FORMAT;
typedef enum {
FILE_BMP, FILE_RGB} INPUT_TYPE;
typedef struct
{
FILE *fp;
const char * file_path;
INPUT_TYPE type;
DWORD height;
DWORD width;
YUV * yuv_raw;
DWORD yuv_size;
RGB * rgb_raw;
DWORD rgb_size;
DWORD start;
int duration;
} ImgFile;
RGB转YUV格式
void RGB2YUV(RGB * rgb_img, YUV * yuv_img, int size) {
int i=0;
for(i=0