相关文章推荐
暴躁的香烟  ·  opencv yuv转rgb - CSDN文库·  2 天前    · 
逆袭的鸵鸟  ·  python opencv yuv 转 ...·  2 天前    · 
逃课的手套  ·  mac安装php7的intl,Error ...·  1 年前    · 
不拘小节的电影票  ·  PowerBi => ...·  1 年前    · 

网上有很多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文档。下面就是其的详细内容总结,希望能于己于人都有所帮助。 速度取决于算法同样的事情,方法不一样,效果也不一样。比如,汽车引擎,可以让你的速度超越马车,却无法超越音速;涡轮引擎,可以轻松 超越音障,却无法飞出地球;如果有火箭发动机,就可以到达火