android-gpuimage里给出了很多滤镜效果,本质都是用shader处理图像。这里分析几个比较有特点的。
完整代码查看https://github.com/andev009/AndroidShaderDemo中的SharpRender 。
1、灰度图像
通过改变亮度将一副彩色图像变成灰色图像。根据sRGB规范,亮度被定义成红,绿,蓝的线性组合,sRGB中基于亮度值的权值向量为
vec3(0.2125, 0.7154, 0.0721),向量rgb与权值向量的点积就是亮度值。
灰度图像的rgb值都为亮度值。在图像处理的过程中,如果要先取得灰度图像,都是先这样处理。
void main()
{
mediump vec3 textureColor = texture2D(u_TextureUnit0, v_TextureCoordinates).rgb;
float luminance = dot(textureColor.rgb, W);
gl_FragColor = vec4(vec3(luminance), 1.0);
}
2、图像卷积(图像锐化)
卷积的作用很多,可以做锐化,模糊等。卷积最好的理解就是一个3X3矩阵和图像上的像素点点积,当然也可以定义5X5这些矩阵。卷积具体的概念就不解释了,重点看如何应用,这里分析图像锐化,gpuimage锐化(sharp filter)的3X3矩阵没有明确定义,不过分析下shader,可知矩阵如下:
float kernelValues[9]=float[9] (
0, -2, 0,
-2, 9, -2,
0, -2, 0
);
知道了卷积矩阵后,还需要取得当前像素的上下左右像素的rgb值,这样才能和矩阵点积。要取得上下左右的像素rgb值,就要取得上下左右的像素的纹理坐标。纹理坐标在shader里的取值范围是[0 ,1],因此纹理坐标的长宽步长分别为:
widthFactor = 1.0f / width//width就是显示图像控件GLSurfaceView的宽度
heightFactor = 1.0f / height//height就是显示图像控件GLSurfaceView的高度
将widthFactor,和heightFactor传到vertex shader里,在vertex shader里u_imageWidthFactor,u_imageHeightFactor就是长宽步长。
这样就可以在vertex shader里取得上下左右的纹理坐标值:
v_TextureCoordinates = a_TextureCoordinates;//当前纹理坐标
mediump vec2 widthHeightStep = vec2(u_imageWidthFactor, u_imageHeightFactor);
mediump vec2 widthNegativeHeightStep = vec2(u_imageWidthFactor, -u_imageHeightFactor);
v_leftTextureCoordinate = a_TextureCoordinates - widthStep;
v_rightTextureCoordinate = a_TextureCoordinates + widthStep;
v_topTextureCoordinate = a_TextureCoordinates + heightStep;
v_bottomTextureCoordinate = a_TextureCoordinates - heightStep;
将上下左右纹理坐标传到fragment shader里,就能取得上下左右像素的rgb值了。
mediump vec3 textureColor = texture2D(u_TextureUnit0, v_TextureCoordinates).rgb;//当前像素rgb
mediump vec3 leftTextureColor = texture2D(u_TextureUnit0, v_leftTextureCoordinate).rgb;
mediump vec3 rightTextureColor = texture2D(u_TextureUnit0, v_rightTextureCoordinate).rgb;
mediump vec3 topTextureColor = texture2D(u_TextureUnit0, v_topTextureCoordinate).rgb;
mediump vec3 bottomTextureColor = texture2D(u_TextureUnit0, v_bottomTextureCoordinate).rgb;
最后用卷积矩阵点积计算最终rgb值
mediump vec3 aroundColor = leftTextureColor * 2.0 + rightTextureColor * 2.0 +
topTextureColor * 2.0 + bottomTextureColor * 2.0;
mediump vec3 finalColor = textureColor * 9.0 - aroundColor;