本文首发在个人我的博客: blog.shenyuanluo.com/,喜欢的朋友欢迎订阅。html
YUV: 是一种颜色空间,基于 YUV
的颜色编码是流媒体的经常使用编码方式,这种表达方式起初是为了彩色电视与黑白电视之间的信号兼容;其中git
Y’CbCr:(也称为 YUV),是 YUV
的压缩版本,不一样之处在于 Y’CbCr
用于 数字图像 领域,YUV
用于 模拟信号 领域;MPEG
、DVD
、摄像机中常说的 YUV
实际上是 Y'CbCr
,两者转换为 RGBA
的转换矩阵是不一样的。github
RGB
输入信号 红色 部分与 RGB
信号亮度值之间的差别(即,当前颜色对 红色 的偏移程度)。RGB
输入信号 蓝色 部分与 RGB
信号亮度值之间的差别(即,当前颜色对 蓝色 的偏移程度)。注意: 如无特殊说明,本文讨论的
YUV
均指Y'CbCr
。算法
Y
,而后 U
,而后 V
。yuv
交叉存储。yuv yuv yuv
)和 planar 采样(yyyy uuuu vvvv
)YUYV YUYV
UYVY UYVY
YYYY UU VV
YUV Y YUV Y
I420:数组
YV12: 性能
Y
是planar采样,UV
是packet采样
NV12: 测试
NV21:优化
RGB: 是一种加色模型,将红(Red
)、绿(Green
)、蓝(Blue
)三原色的色光以不一样的比例相加,以产生多种多样的色光;且三原色的红绿蓝不可能用其余单色光合成。编码
0.0 ~ 1.0
(如在 OpenGL 中对每一个子像素点的表示就是使用这个表示方式)。0 ~ 255
或者 00 ~ FF
(如 RGBA_8888、RGB_565)。bit
表示 0
,1
两种值,可表示的颜色范围为双色,即最传统的黑和白;须要调色板,不过调色板只包含两种颜色。bit
表示,4 个 bit
所可以表示的索引范围是 0~15
,共 16 个。也就是能够表示 16 种颜色。即调色板中包含 16 中颜色。bit
表示。8 个 bit
所可以表示的索引范围是 0~255
,共 256 个。也就是能够表示 256 种颜色。即调色板中包含 256 种颜色。概述: 每个像素用 16 个 bit
(2个字节)来表示,但最高位不用,R 用 5 个 bit
、G 用 5 个 bit
、B 用 5 个 bit
表示。spa
内存示意图:
获取具体像素值方法:(假设 color
为存储某一个像素点的变量)
R = color & 0x7C00
// 获取高字节 5 个 bitG = color & 0x03E0
// 获取中间的 5 个 bitB = color & 0x001F
// 获取低字节 5 个 bit概述: 每个像素用 16 个 bit
(2 个字节)来表示,R 用 5 个 bit
、G 用 6 个 bit
、B 用 5 个 bit
表示。
内存示意图:
获取具体像素值方法:(假设 color
为存储某一个像素点的变量)
R = color & 0xF800
// 获取高字节 5 个 bitG = color & 0x07E0
// 获取中间的 6 个 bitB = color & 0x001F
// 获取低字节 5 个 bit概述: 每个像素用 24 个 bit
(3个字节)来表示,R、G、B 均用 8 bit
表示。
内存示意图:
获取具体像素值方法:(假设 color
为存储某一个像素点的变量)
R = color & 0x0000FF
G = color & 0x00FF00
B = color & 0xFF0000
概述: 每个像素用 32 个 bit
(4个字节)来表示,R、G、B 均用 8 bit
表示,最后 1 个字节保留
内存示意图:
获取具体像素值方法:(假设 color
为存储某一个像素点的变量)
R = color & 0x0000FF00
G = color & 0x00FF0000
B = color & 0xFF000000
注意: 这里的转换矩阵中,当转换为 RGB
读取 YUV
时,须要将 U(Cb)、V(Cr) 的取值范围整数表示时,转换为:[-128, 127]
;浮点数表示时,转换为:[-0.5, 0.5]
。
(这是由于:U(Cb)、V(Cr) 取值范围是 [﹣128, 127]
,对应的浮点数表示为 [﹣0.5, 0.5]
;而在存储时,为了方便存储,跟 Y 数据同样,统一用一个(无符号)字节表示,即取值范围是 [0, 255]
,对应的浮点数表示为:[0, 1]
。)
特别注意: 在 OpenGL
内置的矩阵(如 mat2
、mat3
、mat4
)是 列主序,即须要将下列转换矩阵转换成 转置矩阵 !
常规转换标准:
BT.601 标准:(SD TV)
BT.709 标准:(HD TV)
常规转换标准:
BT.601 标准:(SD TV)
BT.709 标准:(HD TV)
举例:YUV ——> RGB 常规转换矩阵。
r = y + (1.370705 * v);
g = y - (0.337633 * u) - (0.698001 * v);
b = y + (1.732446 * u);
复制代码
从上述算法,能够看到存在许多的浮点运算,而在算法优化中,最好能避免浮点运算(比较耗时)来提升效率。
所以,同时对表达式中全部子项乘以 256
来对结果进行 四舍五入昨晚新的 整数系数,最后再对计算结果再右移 8
位(除以 256
);即,(注意:这里的转换是有损的,精度会有所下降)
256 * r = 256 * y + (256 * 1.370705 * v);
256 * g = 256 * y - (256 * 0.337633 * u) - (256 * 0.698001 * v);
256 * b = 256 * y + (256 * 1.732446 * u);
复制代码
===》
r = ((256 * y + (351 * v))>>8);
g = ((256 * y - (86 * u) - (179 * v))>>8);
b = ((256 * y + (444 * u)) >>8);
复制代码
从上述算法,能够看到存在许多的乘法运算,而乘法一样也很好使,最好能避免乘法运算(使用位移运算代替)来提供效率。
所以,将全部表达式中的子项系数,拆解成整数(该整数必需是 2 的次幂,这样可使用位移运算)相加的形式。
例如:
351 = 256 + 64 + 16 + 8 + 4 + 2 + 1 = 2^8 + 2^6 + 2^4 + 2^3 + 2^2 + 2^1 + 2^0
复制代码
===》
r = (((y<<8) + (v<<8) + (v<<6) + (v<<4) + (v<<3) + (v<<2) + (v<<1) + v) >> 8);
g = (((y<<8) - (u<<6) - (u<<4) - (u<<2) - (u<<1) - (v<<7) - (v<<5) - (v<<4) - (v<<1) - v) >> 8);
b = (((y<<8) + (u<<8) + (u<<7) + (u<<5) + (u<<4) + (u<<3) + (u<<2)) >> 8);
复制代码
在常规转换表达式中,变量的取值范围是已经肯定,Y:[0, 255],U:[-128, 127],V:[-128, 127];那么就可使用一维数组存储结果来提升效率。
所以,将表达式中相关的变量计算结果分别存储在 4 个一位数组中,在使用计算时,直接经过数组查询便可得到表达式相乘结果。
例如:对于表达式 256 * 1.370705 * v
int rv = 0; // 计算 R 值 V 系数
rv = 256 * 1.370705 = 351;
for (int i = 0; i < 256; i++)
{
m_rv[i] = ((i - 128) * rv)>>8;
}
复制代码
===》
r = y + m_rv[v];
g = y - m_gu[u] - m_gv[v];
b = y + m_bu[u];
复制代码
I420 ——> RGB24
),但不写入文件。转换方式 | 循环次数 | 平均耗时(μs/次) | 平均每帧耗时(μs) |
---|---|---|---|
浮点运算 | 50 | 2837788.36 | 6250.64 |
避免浮点运算 | 50 | 2650935.74 | 5839.07 |
避免乘法运算 | 50 | 3031586.02 | 6677.50 |
查表法 | 50 | 2674598.74 | 5891.19 |