[Android-Camera开发]Android平台Camera实时预览数据处理即实时滤镜实现方法探讨(三)--通过Shader实现YUV转换RBG

通过shader将YUV转换成RGB的文章例如 该链接 通过将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第二个参数
代码:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, id_y);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
glUniform1i(gvImageTextureY, 0);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, id_uv);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width/2, height/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data + width*height);
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格式:
precision mediump float;
uniform sampler2D mGLUniformTexture;
uniform sampler2D mGLUniformTexture1;
varying highp vec2 textureCoordinate;

const mat3 yuv2rgb = mat3(
	1, 0, 1.2802,
	1, -0.214821, -0.380589,
	1, 2.127982, 0
);

void main() {
	vec3 yuv = vec3(
		1.1643 * (texture2D(mGLUniformTexture, textureCoordinate).r - 0.0625),
		texture2D(mGLUniformTexture1, textureCoordinate).a - 0.5,
		texture2D(mGLUniformTexture1, textureCoordinate).r - 0.5
	);\
	vec3 rgb = yuv * yuv2rgb;
	gl_FragColor = vec4(rgb, 1);
}

其中,texture2D(mGLUniformTexture, textureCoordinate).r即YUV中的Y,xxx.a即YUV中的V,剩下一个就是U,经过公式转换后设置给gl_FragColor
其余部分基本不变,也不再赘述

下一章探讨多重纹理实现简单滤镜


常量描述
GL_APHPA按照ALPHA值存储纹理单元
GL_LUMINANCE按照亮度值存储纹理单元
GL_LUMINANCE_ALPHA按照亮度和alpha值存储纹理单元
GL_RGB按照RGB成分存储纹理单元
GL_RGBA按照RGBA成分存储纹理单元

The difference between the three single-component texture formats, GL_ALPHA, GL_LUMINANCE and GL_INTENSITY, is in the way the four-component RGBA color vector is generated. If the value for a given texel is X, then the RGBA color vector generated is:

    * GL_ALPHA: RGBA = (0, 0, 0, X)

    * GL_LUMINANCE: RGBA = (X, X, X, 1)

    * GL_INTENSITY: RGBA = (X, X, X, X)

In other words, if we interpret the alpha as transparency, GL_ALPHA would represent a completely black texture with varying transparency, GL_LUMINANCE is an opaque texture with varying color (a grayscale image), and GL_INTENSITY is a combination where both
the color and alpha channel is varying.


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值