YUV与RGB的那些事
对于YUV转RGB这个问题其实之前在之前我们已经实现过了,就在 Opengl ES之YUV数据渲染 一文中,要渲染YUV数据,就需要先将YUV数据转换成RGB数据。
既然这样,那么本文的重点意义在哪里呢?本文主要讲讲YUV到RGB转换过程中的一些理论知识。
我们都知道YUV和RGB的类型比较多,例如YUV类型的又可以分为YUVJ420P和YUV420P,最大的不同是YUVJ420P是使用了JPEG的颜色范围,就是正常的YUV420P的颜色表示范围是16 ~ 235,16表示黑色,235表示白色,而YUVJ420P使用的全颜色域的表示范围,0 ~ 255,0表示黑色,255表示白色。
同时YUV还有BT.601/BT.709/BT.2020三种不同的兼容性标准。
- BT.609是针对标清视频。
- BT.709是针对HD高清视频。
- BT.2020是针对超高清的视频,目前BT.2020用的还比较少。
针对这些不同的标准可以参考以下这个在线转换站点:
YUV与RGB在线转换站点 http://licheng.sakura.ne.jp/hatena6/rgbyc.html
可以看的出这个站点使用的转换公式是非全色域的,也就是局部色域的。
因此如果在视频渲染的过程中如果遇到有色彩偏差的问题可以从YUV到RGB的转换公式是否正确这个方面进行着手调试,例如不同的YUV兼容标准有不同的转换公式,全色域与非全色域有不同的转换公式等。
YUV与RGB的转换公式
- 局部色域的BT.601 YUV转 RGB
R = 1.164(Y-16) + 1.596(Cr-128)
G = 1.164(Y-16) - 0.391(Cb-128) - 0.813(Cr-128)
B = 1.164(Y-16) + 2.018(Cb-128)
- 全色域的BT.601 YUV转 RGB
R = Y + 1.402(Cr-128)
G = Y - 0.344(Cb-128) - 0.714(Cr-128)
B = Y + 1.772(Cb-128)
- 局部色域BT.709 YUV 转 RGB
R = 1.164(Y-16) + 1.793(Cr-128)
G = 1.164(Y-16) - 0.213(Cb-128) - 0.533(Cr-128)
B = 1.164(Y-16) + 2.112(Cb-128)
- 全色域BT.709 YUV 转 RGB
R = Y + 1.280(Cr-128)
G = Y - 0.215(Cb-128) - 0.381(Cr-128)
B = Y + 2.128(Cb-128)
YUV与RGB的转换方式
一般对于YUV与RGB的转换有以下三个比较流行的做法:
- OpenGL shader方式
- libyuv方式
- FFmpeg swscale方式
而在这三种方式当中,又以OpenGL shader和libyuv这两种方式为主,虽然说FFmpeg swscale的方式是FFmpeg自带的,但是因为其转换性能与前两者相比实在是有点大,因此一般不实用这种方式。
在这三种方式中,转换速度最快的就是OpenGL shader的方式,其次是libyuv的方式,但两者的性能相差并不是很大,因此童鞋们可以按需选择。
libyuv的使用方式可以参考https://github.com/lemenkov/libyuv
转换算法优化
- 避免浮点运算
通过上面的转换公式我们可以看到转换的过程中需要进行很多的浮点数的运算,而对于整型运算来说,浮点运算是比较耗时的,如果我们可以将转换公式变成不使用浮点运算的方式的话则可以提升转换效率。
例如针对局部色域的BT.601 YUV转RGB的公式:
R = 1.164(Y-16) + 1.596(Cr-128)
G = 1.164(Y-16) - 0.391(Cb-128) - 0.813(Cr-128)
B = 1.164(Y-16) + 2.018(Cb-128)
我们同时对表达式中所有子项乘以256,然后对结果进行四舍五入得到新的整数系数,最后再对计算结果再右移8位(也就是再除以256)即可得到新的整型转换公式:
256*R = 256*1.164(Y-16) + 256*1.596(Cr-128)
256*G = 256*1.164(Y-16) - 256*0.391(Cb-128) - 256*0.813(Cr-128)
256*B = 256*1.164(Y-16) + 256*2.018(Cb-128)
再两边除以256得=========>
R = (298(Y-16) + 409(Cr-128))>>8
G = (298(Y-16) - 100(Cb-128) - 209(Cr-128))>>8
B = (298(Y-16) + 517(Cb-128))>>8
注意:这里的转换是有损的,精度会有所降低。*
- 避免乘法运算
在学习计算机基础的时候我们就知道位运算的效率要比乘法运算的效率高,因此我们可以将上述公式中的乘法使用位运算的方式进一步提升效率。
例如上述公式中的298可以替换为二进制的位运算:
298= 256+32+8+2=2^8 + 2^5 + 2^3 + 2^1
以此类推,留给童鞋们自行推导…
- 查表
类似LUT滤镜,这里就先不说了,后续介绍LUT滤镜时再细说吧。
关注我,一起进步,人生不止coding!!!
本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/7140.html