• Android平台Camera实时滤镜实现方法探讨(三)--通过Shader实现YUV转换RBG


    http://blog.csdn.net/oshunz/article/details/50055057

    文章例如该链接通过将YUV分成三个纹理,在shader中取出并且经过公式变换,转换成RGB。我尝试了下,显示的是灰色的,可能是这篇文章采用的是planar格式的YUV,与Android平台的packed格式的YUV不同,因此需要在纹理绑定处进行数据指针的修改。

    之前在一篇13年北大硕士的论文基于android平台实时滤镜的设计与实现中提出了一种实现方法,采用双通道,将Y通道与UV通道分别贴图。网上也有单通道经过一些转换再转换的方法,欢迎讨论。

    首先我们探讨下YUV格式

    android平台相机预览数据获取接口onPreviewFrame中默认获取的是YUV420sp格式,例如下图为8X4像素的YUV图像示意图

    即首先将Y信号排列,然后UV数据分别交错排列。其中Y信号数组长度为width * height,UV信号长度为width * heght / 2,数组首元素位置起始于width * height。总长度为width * height * 1.5,相比于采用传统的rgb格式长度减少一半,因此常用语电视信号传输。

    其中Y表示明亮度,也就是灰阶值。UV表示色度,是描述影响色彩及饱和度,用于指定像素颜色。因此,如果我们只使用Y通道,看到的就是原图的灰度图。

    因为GPU并不会根据传入的纹理判断格式,所以我们可以将YUV数据作为RGB数据欺骗GPU,将Y通道与UV通道分成两个纹理传入shader,在shader中利用GPU的优势来进行快速转换。注意要使用两个不同的纹理单元,例如GL_TEXTURE0和GL_TEXTURE1,同样修改glUniform1i第二个参数

    代码:

    [plain] view plain copy
     
    1. glActiveTexture(GL_TEXTURE0);  
    2. glBindTexture(GL_TEXTURE_2D, id_y);  
    3. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);  
    4. glUniform1i(gvImageTextureY, 0);  
    5.   
    6. glActiveTexture(GL_TEXTURE1);  
    7. glBindTexture(GL_TEXTURE_2D, id_uv);  
    8. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width/2, height/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data + width*height);  
    9. glUniform1i(gvImageTextureUV, 1);  

    与直接使用RBGA数据不同,这里的参数采用的是GL_LUMINANCE,与GL_LUMINANCE_ALPHA,与GL_RGBA不同,GL_RGBA单独保存R、G、B、A四个数据,而GL_LUMINANCE将这四个数据合并成一个,因为这样1个Y就可以与1个RGBA对应。GL_LUMINANCE_ALPHA代表首先是亮度,然后是alpha值,这样我们就能将U值与V值分别取出。

    之后通过shader将YUV格式转为RGB格式:

    [plain] view plain copy
     
    1. precision mediump float;  
    2. uniform sampler2D mGLUniformTexture;  
    3. uniform sampler2D mGLUniformTexture1;  
    4. varying highp vec2 textureCoordinate;  
    5.   
    6. const mat3 yuv2rgb = mat3(  
    7.     1, 0, 1.2802,  
    8.     1, -0.214821, -0.380589,  
    9.     1, 2.127982, 0  
    10. );  
    11.   
    12. void main() {  
    13.     vec3 yuv = vec3(  
    14.         1.1643 * (texture2D(mGLUniformTexture, textureCoordinate).r - 0.0625),  
    15.         texture2D(mGLUniformTexture1, textureCoordinate).a - 0.5,  
    16.         texture2D(mGLUniformTexture1, textureCoordinate).r - 0.5  
    17.     );  
    18.     vec3 rgb = yuv * yuv2rgb;  
    19.     gl_FragColor = vec4(rgb, 1);  
    20. }  

    其中,texture2D(mGLUniformTexture, textureCoordinate).r即YUV中的Y数据,texture2D(mGLUniformTexture, textureCoordinate).a即YUV中的V数据,剩下一个就是U,经过矩阵公式转换后就是RGB数据,然后设置给gl_FragColor,OpenGL就可以正确的显示了

    其余部分基本不变,也不再赘述

  • 相关阅读:
    日历
    复数的运算
    大数的计算
    poj 1562
    POJ 1002
    利用正则表达式检测违禁字
    js实现一个闹钟
    jQuery实现五星好评
    jquery实现计算器功能
    横向轮播图
  • 原文地址:https://www.cnblogs.com/jukan/p/6994048.html
Copyright © 2020-2023  润新知