你阳了没
自广州疫情自全部放开,全力复工复产以后你阳了吗?
疫情一放开,首先阳起来的就是那些做自媒体的,各种分享各种蹭流量,生怕错了几个亿一样,反正我是很看不起这些蹭流量的行为。。。
因为很难找到做核酸的地方,也买不到抗原试纸做检测,因此我也不知道自己是否阳了。但是感觉该有的症状都有了,有个周末在家时反复高烧不断,干咳不止,咽痛,喉咙像刀割一样痛苦,说话声音嘶哑,甚至有时候很难说出话来。
目前是重感冒症状,鼻塞、流鼻涕等...
总之一句话,身体是革命的本钱,大家注意身体。。。
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滤镜时再细说吧。
专栏系列
Opengl ES之EGL环境搭建
Opengl ES之着色器
Opengl ES之三角形绘制
Opengl ES之四边形绘制
Opengl ES之纹理贴图
Opengl ES之VBO和VAO
Opengl ES之EBO
Opengl ES之FBO
Opengl ES之PBO
Opengl ES之YUV数据渲染
关注我,一起进步,人生不止coding!!!