视频数据,图像数据在存储中的存储格式主要有RGB和YUV。RGB是多媒体数据进行数据存储采用的主流格式;YUV格式所需存储空间一般是RGB格式存储空间的一半,所以YUV格式主要用于多媒体数据传输中。
1 RGB视频存储格式
计算机彩色显示器显示色彩的原理与彩色电视机一样,都是采用R(Red)、G(Green)、B(Blue)相加混色的原理:通过发射出三种不同强度的电子束,使屏幕内侧覆盖的红、绿、蓝磷光材料发光而产生色彩。这种色彩的表示方法称为RGB色彩空间表示。
RGB的GUID (globally unique identifier全球唯一标识符)格式描述描述如下表所示:
- RGB1
以RGB1(2色位图)为例,比如它的调色板中定义的两种颜色值依次为0x000000(黑色)和0xFFFFFF(白色),那么图像数据00…(每个像素用1位表示)表示对应各像素的颜色为:黑黑白白黑白黑白黑白白白… - RGB565
RGB565使用16位表示一个像素,这16位中的5位用于R,6位用于G,5位用于B。程序中通常使用一个字(WORD,一个字等于两个字节)来操作一个像素。当读出一个像素后,这个字的各个位意义如下:
高字节低字节
R R R R R G G G G G G B B B B B
可以组合使用屏蔽字和移位操作来得到RGB各分量的值:
#define RGB565_MASK_RED 0xF800
#define RGB565_MASK_GREEN 0x07E0
#define RGB565_MASK_BLUE 0x001F
R = (wPixel & RGB565_MASK_RED) >> 11; // 取值范围0-31
G = (wPixel & RGB565_MASK_GREEN) >> 5; // 取值范围0-63
B = wPixel & RGB565_MASK_BLUE; // 取值范围0-31 - RGB555
RGB555是另一种16位的RGB格式,RGB分量都用5位表示(剩下的1位不用)。使用一个字读出一个像素后,这个字的各个位意义如下:
高字节低字节
X R R R R G G G G G B B B B B (X表示不用,可以忽略)
可以组合使用屏蔽字和移位操作来得到RGB各分量的值:
#define RGB555_MASK_RED 0x7C00
#define RGB555_MASK_GREEN 0x03E0
#define RGB555_MASK_BLUE 0x001F
R = (wPixel & RGB555_MASK_RED) >> 10; // 取值范围0-31
G = (wPixel & RGB555_MASK_GREEN) >> 5; // 取值范围0-31
B = wPixel & RGB555_MASK_BLUE; // 取值范围0-31 - RGB24
RGB24使用24位来表示一个像素,RGB分量都用8位表示,取值范围为0-255。注意在内存中RGB各分量的排列顺序为:BGR BGR BGR…。通常可以使用RGBTRIPLE数据结构来操作一个像素,它的定义为:
typedef struct tagRGBTRIPLE {
BYTE rgbtBlue; // 蓝色分量
BYTE rgbtGreen; // 绿色分量
BYTE rgbtRed; // 红色分量
} RGBTRIPLE; - RGB32
RGB32使用32位来表示一个像素,RGB分量各用去8位,剩下的8位用作Alpha通道或者不用。(ARGB32就是带Alpha通道的 RGB32。)注意在内存中RGB各分量的排列顺序为:BGRA BGRA BGRA…。通常可以使用RGBQUAD数据结构来操作一个像素,它的定义为:
typedef struct tagRGBQUAD {
BYTE rgbBlue; // 蓝色分量
BYTE rgbGreen; // 绿色分量
BYTE rgbRed; // 红色分量
BYTE rgbReserved; // 保留字节(用作Alpha通道或忽略)
} RGBQUAD;
2 YUV视频存储格式
2.1 YUV概述
在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD摄像机进行摄像,然后把摄得的彩色图像信号经分色、分别放大校正后得到 RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y(即U)、B-Y(即V),最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。
采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V分量,那么这样表示的图像就是黑白灰度图像。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号。
本文讲述的格式全部使用每个像素位置 8 位的方式来编码 Y 频道(也称为灯光频道),并使用每样例 8 位的方式来编码每个 U 或 V 色度样例。但是,大多数 YUV 格式平均使用的每像素位数都少于 24 位,这是因为它们包含的 U 和 V 样例比 Y 样例要少。
注在本文中,U 一词相当于 Cb,V 一词相当于 Cr。
2.2常见YUV的格式
在DirectShow 中,常见的YUV格式有 YUY2、YUYV、YVYU、UYVY、AYUV、Y41P、Y411、Y211、IF09、IYUV、YV12、YVU9、YUV411、 YUV420等。作为视频媒体类型的辅助说明类型(Subtype),它们对应的GUID(Globally Unique Identifier)如下表所示。
表2.2 YUV的GUID描述
YUV的GUID描述符 描述符说明
MEDIASUBTYPE_YUY2 YUY2 以4:2:2方式打包
MEDIASUBTYPE_YUYV YUYV 实际格式与YUY2相同
MEDIASUBTYPE_YVYU YVYU 以4:2:2方式打包
MEDIASUBTYPE_UYVY UYVY 以4:2:2方式打包
MEDIASUBTYPE_AYUV AYUV Alpha通道的4:4:4 YUV格式
MEDIASUBTYPE_Y41P Y41P 以4:1:1方式打包
MEDIASUBTYPE_Y411 Y411 实际格式与Y41P相同
MEDIASUBTYPE_Y211 Y211
MEDIASUBTYPE_IF09 IF09格式
MEDIASUBTYPE_IYUV IYUV格式
MEDIASUBTYPE_YV12 YV12格式
MEDIASUBTYPE_YVU9 YVU9格式
2.3 YUV主要采样格式
主要的采样格式有YCbCr 4:2:0、YCbCr 4:2:2、YCbCr 4:1:1和 YCbCr 4:4:4。其中YCbCr 4:1:1 比较常用,其含义为:每个点保存一个 8bit 的亮度值(也就是Y值),每 2x2 个点保存一个 Cr 和Cb 值, 图像在肉眼中的感觉不会起太大的变化。所以,原来用 RGB(R,G,B 都是 8bit unsigned) 模型, 1个点需要 8x3=24 bits,若4:4:4按采样后,YUV仍各占8bit。按4:1:1采样后,而现在一个点平均仅需要 8+(8/4)+(8/4)=12bits。这样就把图像的数据压缩了一半。
YUV 的优点之一是,色度频道的采样率可比 Y 频道低,同时不会明显降低视觉质量。有一种表示法可用来描述 U 和 V 与 Y 的采样频率比例,这个表示法称为 A:B:C 表示法:
• 4:4:4:表示色度频道没有下采样。
• 4:2:2:表示 2:1 的水平下采样,没有垂直下采样。对于每两个 U 样例或 V 样例,每个扫描行都包含四个 Y 样例。
• 4:2:0:表示 2:1 的水平下采样,2:1 的垂直下采样。
• 4:1:1:表示 4:1 的水平下采样,没有垂直下采样。对于每个 U 样例或 V 样例,每个扫描行都包含四个 Y 样例。
2.3.1 YUV采样格式图示 - YUV 4:4:4 采样
下图显示了 4:4:4 图片中使用的采样网格。灯光样例用叉来表示,色度样例则用圈表示。
图2.3 YUV 4:2:0 样例位置(MPEG-1 方案)
- 4:4:4 格式,每像素 32 位
推荐一个 4:4:4 格式,FOURCC 码为 AYUV。这是一个打包格式,其中每个像素都被编码为四个连续字节,其组织顺序如下所示。
图2.13 NV12 内存布局
- 将4:2:0 YUV 转换为 4:2:2 YUV
将 4:2:0 YUV 转换为 4:2:2 YUV 需要系数为 2 的垂直上转换。本节讲述了一个执行上转换的方法示例。该方法假设视频图片为逐行扫描。
注 4:2:0 到 4:2:2 隔行扫描转换过程会出现不常见的问题,难以实现。本文不会对转换从 4:2:0 到 4:2:2 的隔行扫描时出现的问题进行解决。
让输入色度样例的每个垂直行都成为一个数组 Cin[],其范围为从 0 到 N - 1。输出图像上相应的垂直行则会成为数组 Cout[],其范围为从 0 到 2N - 1。要转换每个垂直行,请执行下列过程:
Cout[0]= Cin[0];
Cout[1]= clip((9 * (Cin[0] + Cin[1]) – (Cin[0] + Cin[2]) + 8) >> 4);
Cout[2]= Cin[1];
Cout[3]= clip((9 * (Cin[1] + Cin[2]) - (Cin[0] + Cin[3]) + 8) >> 4);
Cout[4]= Cin[2]
Cout[5]= clip((9 * (Cin[2] + Cin[3]) - (Cin[1] + Cin[4]) + 8) >> 4);
…
Cout[2i]= Cin[i]
Cout[2i+1] = clip((9 * (Cin[i] + Cin[i+1]) - (Cin[i-1] + Cin[i+2]) + 8) >> 4);
…
Cout[2N-3] = clip((9 * (Cin[N-2] + Cin[N-1]) - (Cin[N-3] + Cin[N-1]) + 8) >> 4);
Cout[2N-2] = Cin[N-1];
Cout[2*N-1] = clip((9 * (Cin[N-1] + Cin[N-1]) - (Cin[N-2] + Cin[N-1]) + 8) >> 4);
其中 clip() 表示剪辑范围为 [0…255]。
注用于处理边缘的等式在计算上可以进行简化。这些等式以这种形式显示,是为了说明图片边缘的附着效果。
实际上,这种方法会通过在四个相邻像素上插入曲线,并趋向两个最近的像素值进行加权,来计算每个缺少的值(图2.14)。此示例中使用的这个特定插入方法使用一个众所周知的方法来计算半整数位置缺少的样例,这个方法称为 Catmull-Rom 插入,也称为立方回旋插入。
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/rfx/49002.html