网上有很多YUV到RGB的转化程序,不过他们基本上都是基于CPU进行计算,基于CPU计算大体上有一下的一些方法,最原始的肯定是根据转换公式直接进行浮点运算,要想提高速度,可以用左移和右移操作,将浮点运算变成整数运算,这样转化的速度会成倍的提高。另外还可以用查表法,因为YUV都是在0~255之间,他们总是有范围的,先生成一个很大的查找表,直接对每一个YUV分量查找出RGB值,当然这个查找表会很大,可以用部分查找的方法来缩小查找表的容量。
用CPU计算比较好的方法就是利用CPU的SSE指令,有一个专门的名词是来形容SSE的,那就是“单指令流多数据流”,意思就是他可以一次对多个数据进行计算,当然速度是非常快的。
在这里,我主要写一下我用shader做转化的方法,首先,当然是介绍一下YUV:
Windows下YUV格式的介绍在MSDN上介绍的非常全面。YUV的格式有很多种,有444,422,420之分,并且每一种具体的格式也有许多不同的标准。具体在MSDN的以下地址上有详细的介绍:
http://www.microsoft.com/china/MSDN/library/enterprisedevelopment/softwaredev/VideoRende8BitYUV.mspx?mfr=true
不过对于写程序来说,我只关心每种格式的内存布局方式。
YUV分为打包格式(packed)和平面格式(planar),平面格式中YUV的每个分量是分开存储的,一般先存储所有的Y分量,再存储所有的U分量,然后存储所有的V分量;打包方式则是YUV的每个分量并没有分开存储,而是存储在一起。例如:
打包格式(图片来自于MSDN),422中的YUY2格式:
我用到的就是YUV420的IMC4格式,是一种平面格式。这种格式的特点是先存储所有的Y分量,总共有多少像素,就有多少个Y分量。紧接着,存储U分量,再存储V分量,U和V分别都只占总像素的1/4,所以,我所用的YUV420格式的一帧所占的内存空间可以这样计算:
m_FrameHeight; //视频高度
m_FrameWidth; //视频宽度
m_ImgSize = m_FrameWidth * m_FrameHeight; //宽 * 高
m_FrameSize = m_ImgSize + (m_ImgSize >> 1); //YUV视频一帧的大小,其中的右移相当于/2
所以每个分量的内存地址可以按如下方式计算:
unsigned char* cTemp[3];
cTemp[0] = m_yuv + m_FrameSize * n; //y分量地址
cTemp[1] = cTemp[0] + m_ImgSize; //u分量地址
cTemp[2] = cTemp[1] + (m_ImgSize >> 2); //v分量地址
m_yuv是整段视频的首地址,也就是指向整段视频的指针;n是当前帧的序号。
知道了每一帧的YUV各分量的地址,再进行转换就比较容易了。有很多公式可以进行转换,我所用到的转换公式是这样的:
R = y + 1.4022 * (v - 128)
G = y - 0.3456 * (u - 128) - 0.7145 * (v - 128)
B = y + 1.771 * (u - 128)
下面开始利用Shader按照这个转换公式来进行计算,由于我也是刚刚开始接触shader编程,对于shader的工作方式也不是十分熟悉,我也只是按照自己的理解来进行编程。
首先,显卡在运行shader程序的时候,是很多像素并行计算的,所以转换的速度很快,但是我发现针对每一个像素,shader只知道他自己的像素信息,包括他自己的颜色(RGB)、深度、纹理坐标等等。对于其他像素的信息一无所知,例如,一个红色像素只知道他自己应该显示成红色,对于他左边的像素是什么颜色,他不会知道,更不用说隔他更远的像素了。于是他仅仅只能利用自己的信息来进行运算。这样就遇到一个问题,由于YUV的每个分量存储的位置相隔很远,要在一个shader程序中分别得到一个像素相应的YUV分量数据,就要对内存的数据排列格式做相应的调整。我所用的方法是将视频的数据格式调整成按照YUVYUVYUV...一一对应的格式来排列,这样,我可以先把YUV的数据假装是RGB的数据送入到纹理中,骗过显卡,然后再在shader中用转换公式来进行计算。由于YUV分量的数据范围也是0~255之间的,所以这种方式是可以成功的。
(这里可能说的不对,我认为每一个像素在运行shader的时候,应该是有方法能够得到除自己以外其他像素信息的,但是我学习shader还只有一个星期的时间,可能还不知道方法,如果有这样的方法的话,那么转换的效率会更高,因为我不需要在内存中再花时间来做数据的排列工作。但这个可能要对shader的工作原理非常清楚,等以后我熟悉了,再来重新写一个程序。)
下面开始,首先是排列过程,这个过程发生在内存中:
for(y=0; y < m_FrameHeight; y++)
{
for(x=0; x < m_FrameWidth; x++)
{
l = y * m_FrameWidth + x;
m = (y / 2) * (m_FrameWidth / 2) + x / 2;
m_Data[3 * l] = cTemp[0][l]; //y
m_Data[3 * l + 1] = cTemp[1][m]; //u
m_Data[3 * l + 2] = cTemp[2][m]; //v
}
}
排列的方法很简单,只要理解了上面的那个内存布局结构,就很容易知道了。
然后将排列好的YUV数据送入到纹理中,在每一帧的渲染之前,都运行shader程序。其中shader程序代码如下:
顶点着色器Vertex Shader:
void main()
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = ftransform();
}
片段着色器Fragment Shader:
uniform sampler2D tex;
void main()
{
vec4 yuv = texture2D(tex,gl_TexCoord[0].st);
vec4 color;
color.r =yuv.r + 1.4022 * yuv.b - 0.7011;
color.r = (color.r < 0.0) ? 0.0 : ((color.r > 1.0) ? 1.0 : color.r);
color.g =yuv.r - 0.3456 * yuv.g - 0.7145 * yuv.b + 0.53005;
color.g = (color.g < 0.0) ? 0.0 : ((color.g > 1.0) ? 1.0 : color.g);
color.b =yuv.r + 1.771 * yuv.g - 0.8855;
color.b = (color.b < 0.0) ? 0.0 : ((color.b > 1.0) ? 1.0 : color.b);
gl_FragColor = color;
}
其中为什么会有-0.7011、0.53005、0.8855这样的常数,那是因为颜色数据从着色器中的到的时候,已经转化成了浮点数的形式,范围为0.0~1.0之间,所以转换公式后面的系数也要做相应的变化。
Unity 工具之
YUV
(
YUV
420 :I420,YV12,NV12,NV21)
使用
shader
转为
RGB
显示 封装
YUV
420To
RGB
Wrapper
1、首先根据
YUV
对应格式的
YUV
的排列方式,拆分
YUV
;
2、然后,在通过
YUV
与
RGB
转换
对应公式,进行
转换
;
3、最后,
shader
方式显示出来;
4、调用接口,
YUV
420To
RGB
Wrapper.
YUV
420To
RGB
(
YUV
420
yuv
420_Format, byte[] data, int width, int height, Renderer renderer),设定
YUV
格式,数据,宽、高、以及目标的渲染的 Renderer ,即可
实现
YUV
转
RGB
////本文由锈水管原创。 网上有很多
YUV
到
RGB
的转化程序,不过他们基本上都是基于CPU进行计算,基于CPU计算大体上有一下的一些方法,最原始的肯定是根据
转换
公式直接进行浮点运算,要想提高速度,可以用左移和右移操作,将浮点运算变成整数运算,这样转化的速度会成倍的提高。另外还可以用查表法,因为
YUV
都是在0~255之间,他们总是有范围的,先生成一个很大的查找表,直接对每一个YU
YUV
图片数据以及
YUV
转
rgb
问题
2.
YUV
数据格式
颜色都可以通过原色 red green blue通过不同的比例混合出来,这种既是
RGB
数据格式图像;而
YUV
, Y表示亮度,U V表示色差信息(分别表示blue 和 Red的色差信息),通过
YUV
三个分量值,可以计算出
RGB
。
YUV
类型数据分为很多的形式,比如
YUV
444,
YUV
422或者
YUV
420,本文主要对
YUV
420格式数据进行分析。假设图片宽高分别为Width和
shader
中颜色是以
rgb
a表示,但是很多时候我们需要将其
转换
成HSV颜色空间,或者将某个HSV颜色转成
RGB
进行计算,比如一些后期效果需要调整画面的色相(Hue),或者降低画面的饱和度(Saturation),因此有必要在
shader
中
实现
HSV和
RGB
颜色空间互转的函数,
RGB
和HSV互转网上可以搜到很多现成的方式,这里提高一组简短的
shader
实现
:
float3
RGB
2HSV
这两天公众号发布了篇如何将 图片
转换
字符画 效果的文章,不过具体的
实现
是在 CPU 上的。Android
实现
图片 转 字符画 效果Android
实现
视频 转 字符画效果那天在...
最近,有位读者大人在后台反馈:在参加一场面试的时候,面试官要求他用
shader
实现
图像格式
RGB
转
YUV
,他听了之后一脸懵,然后悻悻地对面试官说,他只用
shader
做过
YUV
转
RGB
,不知道
RGB
转
YUV
是个什么思路。
针对他的这个疑惑,今天专门写文章介绍一下如何
使用
OpenGL
实现
RGB
到
YUV
的图像格式
转换
,帮助读者大人化解此类问题。
YUV
看图工具推荐
有读者大人让推荐一个
YUV
看图软件,由于手头的工具没法分享出来,又在 Github 上找了一圈发现这.
朋友曾经给我推荐了一个有关代码优化的pdf文档《让你的软件飞起来》,看完之后,感受颇深。为了推广其,同时也为了自己加深印象,故将其总结为word文档。下面就是其的详细内容总结,希望能于己于人都有所帮助。 速度取决于算法同样的事情,方法不一样,效果也不一样。比如,汽车引擎,可以让你的速度超越马车,却无法超越音速;涡轮引擎,可以轻松 超越音障,却无法飞出地球;如果有火箭发动机,就可以到达火