yjguo的个人博客分享 http://blog.sciencenet.cn/u/yjguo

博文

基于OpenGL Shader的颜色空间转换

已有 10086 次阅读 2015-8-11 21:40 |个人分类:OpenGL|系统分类:科研笔记

为了某个原因成文于2013年,实际上,本文的意义并不在创新点,而在于工程实践的一个例子。从最新发展来看,用OpenCL kernel来完成也非常合适。


    YUVRGBA是计算机系统的两个重要颜色空间,分别用于视频和图形系统。随着个人电脑和消费电子行业对用户体验的不断追求,产生了这两种颜色空间的相互转换要求。本文以NV12和RGBA8888格式为例,探讨了基于OpenGL shader的转换方法,揭示了将原始问题映射到图形领域的难点,并给出了直观的解决方法。实践证明,此方法利用GPGPU(GeneralPurpose GPU)通用计算功能进行硬件加速,在大幅降低CPU利用率的同时显著提高了效率。

关键词    OpenGL, Shader,颜色空间转换, 通用计算


1.引言

当前计算机系统的主要颜色空间有两个,分别为YUV[[1]]和RGBA。其中,YUV在视频系统中被采用,Y代表亮度信号,UV代表色度信号,这种格式被提出的初衷是为了用亮度信号Y来兼容老式的黑白电视,使得黑白电视机也可以接收彩色电视信号。RGBA分别表示一个像素的红、绿、蓝和alpha分量,在图形系统中被广泛采用,比如Direct3D和OpenGL都是对像素RGBA空间的处理。为了使用3D硬件加速功能完成对视频特效的复杂后处理,需要将YUV颜色空间转换到RGBA空间;而诸如WiDi(Wireless Display)[[2]]和Miracast[[3]]等标准则要求将RGBA空间转换为YUV空间。

为了提高颜色空间转换的效率,较好的方法是基于shader借助GPGPU通用计算的硬件加速功能完成。本文以YUV空间中最典型的NV12格式和RGBA空间中最典型的RGBA8888格式为例,探讨了如何基于OpenGL shader[[4]]进行进行颜色空间转换。

2.问题域映射

如下图1所示的高hw的像素区域,共计h*w列个像素,其中,L(i,j) 表示第i行第j列的像素,i=0..h-1j=0..w-1。其RGBA8888的格式表示如图2所示,共计4*w*h个字节,其中,L(i,j)rL(i,j)gL(i,j)bL(i,j)a分别像素L(i,j)的红、绿、蓝和alpha分量,每个分量占1个字节。其NV12格式的表示如图3所示,共计w*(h+h/2)个字节。根据NV12格式的定义,Y分量和UV分量分开存储,在Y分量填充完毕后再填充UV分量;每个像素生成一个Y分量,每4个像素生成一个U分量和一个V分量。如图3所示,L(i,j)y表示对应像素的Y分量,占1个字节;而L(2k~2k+1,2p~2p+1)uL(2k~2k+1, 2p~2p+1)v则表示来自相邻的2*2个像素L(2k,2p)L(2k+1,2p)L(2k,2p+1)L(2k+1,2p+1)所对应的UV分量,其中k=0..h/2,p=0..w/2,每个分量占1个字节,两者交替存储。因此,颜色空间的转换,也就是图2RGBA8888格式表示和图3的NV12格式表示之间的相互转换。

1wh的像素区域

2wh的像素区域的RGBA888格式表示

3wh的像素区域的NV12格式表示

将此问题映射到图形领域,也就意味着将转换中的源格式表示作为OpenGL纹理(texture),采用GL_NEAREST采样参数,将目标格式表示当做RT(RenderTarget,绘制目标),简单绘制一个覆盖全部RT的矩形,绘制过程使用的shader基于两个颜色空间的转换公式,如图4所示[[5]],其中,Cb是U分量,Cr是V分量。于是,此问题就进一步的被简化为如何选择合适的纹理格式和RT格式,以及设置正确的纹理坐标了。

4)YUV和RGB间的转换公式

3.NV12RGBA8888的转换

NV12格式的Y分量和UV分量分开存储,因此,将Y分量和NV分量分别当做一个纹理。如图5所示,Y分量的纹理格式为GL_ALPHA,宽w高h,也就是说每个像素的Y分量是一个texel(纹理单元)。UV分量的纹理格式为GL_LUMINANCE_ALPHA,宽w/2,高h/2,也就是说原始问题中的2*2个像素所对应的一个U分量和一个V分量构成了一个纹理单元。RenderTarget的格式为GL_RGBA,宽w高h,也就是说每个像素的RGBA四个分量构成了RT中的一个fragment(片元)。接下来的任务就是寻找合适的纹理映射方法,使得Y纹理对象中的一个纹理单元对应一个片元,而UV纹理对象中的一个纹理单元对应四个片元。

5) NV12格式到RGBA8888的纹理映射

将目标矩形(RenderTarget)左下角的纹理坐标设置为(0,0),右上角纹理坐标为(1.0,1.0),可以实现正确的纹理采样,获得计算每个片元的红绿蓝分量所需要的Y分量和UV分量的值,如图5所示。证明过程如下,不妨假设在RenderTarget中的四个片元ABCD处于第2m列、第2m+1列、第2n行、第2n+1列,则光栅化后插值得到的纹理坐标分别为((2m+0.5)/w,(2n+0.5)/h)、((2m+1.5)/w, (2n+0.5)/h)、((2m+0.5)/w,(2n+1.5)/h)和((2m+1.5)/w, (2n+1.5)/h),因为OpenGL规范规定以每个片元的中心点数值表示该片元的属性,因此需要加上0.5的偏移,这四个纹理坐标在Y纹理对象中刚好对应着abcd四个纹理单元,两者是一一对应的关系。而这四个纹理坐标可变形为((m+0.5/2)/(w/2),(n+0.5/2)/(h/2))、((m+1.5/2)/(w/2), (n+0.5/2)/(h/2))、((m+0.5/2)/(w/2), (n+1.5/2)/(h/2))和((m+1.5/2)/(w/2),(n+1.5/2)/(h/2)),在UV纹理对象中对应着第m列和n行的纹理单元内部的四个采样点,见图5中四个小圆所示,因为我们使用GL_NEARST采样参数,因此,最终的采样结果就是该纹理单元,即四个片元对应着一个UV纹理单元,符合NV12的格式定义。至此,简要证明完毕。

获得每个片元对应的Y分量和UV分量的值后,就可以根据图3的公式结合片元格式来编写shader,实现从YUV到RGBA空间的转换。

4.RGBA8888NV12的转换

RGBA8888格式表示可以被看做宽wh的纹理对象,其纹理格式为GL_RGBA。将NV12格式当做RT(RenderTarget)稍微有些麻烦,因为在graphics领域,RT都是使用RGBA颜色空间的格式。由于NV12格式的Y分量和UV分量分开存储,因此,在格式转换时也分别考量。如图6右侧所示,RT的格式为GL_RGBA,宽为w/4,高为(h+h/2),由上下两部分组成,上半部分表示Y分量,高度为h,每个片元的RGBA值对应着四个Y值,比如,图中的abcd四个纹理单元的Y值被映射到一个片元中;下半部分表示UV分量,高度为h/2,每个片元的RGBA值对应着连续的两组U值和V值,比如,图中的abef四个纹理单元对应的U值和V值被分别映射到片元的RG分量中,而cdgh四个纹理单元对应的U值和V值被分别映射到片元的BA分量中。

6 RGBA8888NV12的纹理映射

为了分别计算RT中的Y分量和UV分量,可以用glViewport进行区分设置,也就是说,glViewport(0,0,w/4,h/2)使所绘制的矩形仅覆盖UV分量部分,而glViewport(0,h/2, w/4, h)使所绘制的矩形仅覆盖Y分量部分。

在计算Y分量时,由于一个片元需要四个纹理采样值,以填充其片元格式中的RGBA四个分量,因此,每个片元被赋予4个纹理坐标。将目标矩形左下角的4个纹理坐标设置为(0.0-1.5/w,0.0)(0.0-0.5/w,0.0)(0.0+0.5/w,0.0)(0.0+1.5/w,0.0),右上角纹理坐标设置为(1.0-1.5/w,1.0)(1.0-0.5/w,1.0)(1.0+0.5/w,1.0)(1.0+1.5/w,1.0)可以实现正确的纹理采样。具体的证明过程类同与第三节,不再赘述。

在计算UV分量时,根据NV12格式定义,四个纹理单元生成一个U值和一个V值,但并没有规定具体算法,在本文实践中,以左下角纹理单元的UV值作为四个纹理单元共有的UV值。所以,每个片元只需要2个纹理坐标,得到两组UV值,填充其片元格式中的RGBA四个分量。将目标矩形左下角的2个纹理坐标设置为(0.0-1.5/w,0.0-0.5/h)和(0.0+0.5/w,0.0-0.5/h),右上角纹理坐标设置为(1.0-1.5/w,1.0-0.5/h)和(1.0+0.5/w,1.0-0.5/h),可以实现正确的纹理采样。具体的证明过程类同与第三节,不再赘述。

实际上,可以使用非常直观的方法来获取正确的纹理坐标组,首先假设目标矩形左下角纹理坐标为(0,0),右上角纹理坐标为(1,1),根据纹理和RT的宽高比例,可以知道多少个纹理单元被映射到一个片元。该片元插值得到的纹理坐标将正好处于这些纹理单元的中心点,在此基础上,考虑具体物理意义,将纹理坐标进行+-0.5和+-1.5等偏移,即可得到正确的纹理坐标。

5.结语

本文以NV12和RGBA8888格式为例,说明了如何基于shader进行颜色空间转换,其他格式的转换也是类似的。实践证明,这种方法利用GPGPU通用计算的硬件加速功能,在大幅降低CPU利用率的同时显著提高了效率。鉴于目前大屏幕显示设备的普及,像素宽度往往都满足硬件的字节对齐要求,因此,本文没有对字节对齐进行讨论。

 

参考文献


[1]YUV pixel formats, http://www.fourcc.org/yuv.php

[2]Intel Wireless Display, http://www.intel.com/content/www/us/en/architecture-and-technology/intel-wireless-display.html

[3]Wi-Fi CERTIFIED MiracastTM, http://www.wi-fi.org/wi-fi-certified-miracast%E2%84%A2

[4]John Kessenich, LunarG, The OpenGL Shading Language, 3-Aug-2012, http://www.opengl.org/registry/doc/GLSLangSpec.4.30.6.pdf  

[5] Keith Jack, Video Demystified (FifthEdition), 2007 Elsevier Inc.





https://blog.sciencenet.cn/blog-1420268-912333.html

上一篇:3D Graphics开发基础综述
下一篇:EGL资源的数据共享应用和底层驱动实现
收藏 IP: 116.233.97.*| 热度|

0

该博文允许注册用户评论 请点击登录 评论 (0 个评论)

数据加载中...

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-12-24 03:40

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部