相机滤镜N:卷积内核实现滤镜效果
上一个章节,我们通过改变着色器中RGB的颜色值,实现了灰色滤镜;本章节讲解另外一张滤镜开发的基本形式
章节目录:
1 滤镜实现方式
2 卷积内核基础介绍
3 着色器实现
3.1 正常滤镜效果
3.2 浮雕效果
1 滤镜实现方式
相机滤镜,本系列讲解的主要通过opengles实现
opengles又主要分为通过卷积内核对图像进行处理和通过调整RGB通过对图像进行处理,接下里会一 一讲解这两种方式
2 卷积内核基础介绍
相机中的滤镜开发的类型之一是:基于卷积计算开发的,因此本小节计算的原理进行简要的介绍。卷积是一种很常见的数字图像处理操作,其可以用来过滤一幅图像。实现过滤的方法是计算源图像与卷积内核之间的积,所谓卷积内核是指一个nxn的矩阵,n一般为奇数。进行卷积计算时将卷积内核对待处理图像的每个像素都应用一次,具体的计算思路如图下图所示:
卷积内核图中可以看出,卷积计算将需要处理的图片中的每个像素计的计算方法如下
-
首先将卷积内核中心的元素对准当前待处理的像素,此时卷积内核素也各自对应到了像素
-
然后将卷积内核中的各元素与其对应的像素的颜色值相乘
-
最后将所有的乘积加权求和即可得到外理后图片中该位置的像素的颜色值
由以上公式可知,如果卷积内核的为以下值时,处理前后,像素对应的颜色值时不变的:
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f
通过改变卷积内核各个位置的值,我们可以实现各种滤镜效果
3 着色器实现
根据以上理论知识,我们来实现下基于OPENGL 2.0 的顶点作色器和片元作色器实现
顶点作色器,image3x3TextureSampling_vertext.glsl
attribute vec4 a_position;//应用层传递的顶点坐标
attribute vec2 a_texcoord;//纹理坐标
uniform highp float texelWidth; //从应用层传递的纹理坐标左右偏移量;取值范围,单位像素的0~5倍距离
uniform highp float texelHeight; //从应用层传递的纹理坐标上下偏移量;取值范围,单位像素的0~5倍距离
varying vec2 textureCoordinate;
varying vec2 leftTextureCoordinate;
varying vec2 rightTextureCoordinate;
varying vec2 topTextureCoordinate;
varying vec2 topLeftTextureCoordinate;
varying vec2 topRightTextureCoordinate;
varying vec2 bottomTextureCoordinate;
varying vec2 bottomLeftTextureCoordinate;
varying vec2 bottomRightTextureCoordinate;
void main()
{
gl_Position = a_position;
vec2 widthStep = vec2(texelWidth, 0.0);
vec2 heightStep = vec2(0.0, texelHeight);
vec2 widthHeightStep = vec2(texelWidth, texelHeight);
vec2 widthNegativeHeightStep = vec2(texelWidth, -texelHeight);
//当前要处理的纹理的像素坐标
textureCoordinate = a_texcoord.xy;//当前要处理的像素坐标
//当前要处理的像素的周围八个像素的坐标
leftTextureCoordinate = a_texcoord.xy - widthStep;//
rightTextureCoordinate = a_texcoord.xy + widthStep;
topTextureCoordinate = a_texcoord.xy - heightStep;
topLeftTextureCoordinate = a_texcoord.xy - widthHeightStep;
topRightTextureCoordinate = a_texcoord.xy + widthNegativeHeightStep;
bottomTextureCoordinate = a_texcoord.xy + heightStep;
bottomLeftTextureCoordinate = a_texcoord.xy - widthNegativeHeightStep;
bottomRightTextureCoordinate = a_texcoord.xy + widthHeightStep;
}
texelWidth和texelHeight是指当前要处理的像素,距离它周围的八个像素x和y方向的跨度,计算方式如下:
//lineSize 取值范围0~5,默认为1
//width,height表示要处理的图片或者帧数据的宽和高
texelWidth = lineSize / width;
texelHeight = lineSize / height;
片元着色器,image3x3TextureSampling_fragment.glsl
precision mediump float;
uniform sampler2D tex_sampler_0;//应用层传递的纹理内容
uniform mediump mat3 convolutionMatrix;//3*3的卷积内核
//从顶点着色器传递过来的各个像素纹理坐标
varying vec2 textureCoordinate;
varying vec2 leftTextureCoordinate;
varying vec2 rightTextureCoordinate;
varying vec2 topTextureCoordinate;
varying vec2 topLeftTextureCoordinate;
varying vec2 topRightTextureCoordinate;
varying vec2 bottomTextureCoordinate;
varying vec2 bottomLeftTextureCoordinate;
varying vec2 bottomRightTextureCoordinate;
void main()
{
//求卷积内核各个值对应的各个像素的值
mediump vec4 bottomColor = texture2D(tex_sampler_0, bottomTextureCoordinate);
mediump vec4 bottomLeftColor = texture2D(tex_sampler_0, bottomLeftTextureCoordinate);
mediump vec4 bottomRightColor = texture2D(tex_sampler_0, bottomRightTextureCoordinate);
mediump vec4 centerColor = texture2D(tex_sampler_0, textureCoordinate);
mediump vec4 leftColor = texture2D(tex_sampler_0, leftTextureCoordinate);
mediump vec4 rightColor = texture2D(tex_sampler_0, rightTextureCoordinate);
mediump vec4 topColor = texture2D(tex_sampler_0, topTextureCoordinate);
mediump vec4 topRightColor = texture2D(tex_sampler_0, topRightTextureCoordinate);
mediump vec4 topLeftColor = texture2D(tex_sampler_0, topLeftTextureCoordinate);
//乘积加权求和,得出当前片元的颜色
mediump vec4 resultColor = topLeftColor * convolutionMatrix[0][0] + topColor * convolutionMatrix[0][1] + topRightColor * convolutionMatrix[0][2];
resultColor += leftColor * convolutionMatrix[1][0] + centerColor * convolutionMatrix[1][1] + rightColor * convolutionMatrix[1][2];
resultColor += bottomLeftColor * convolutionMatrix[2][0] + bottomColor * convolutionMatrix[2][1] + bottomRightColor * convolutionMatrix[2][2];
gl_FragColor = resultColor;
}
convolutionMatrix表示应用层传递的卷积内核矩阵信息
通过传入不同的convolutionMatrix值,我们实现不同的滤镜效果
3.1 正常滤镜效果
有以上可知,正常效果的卷积内核为:
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f
通过前面的计算公式,可以计算出,原象素和目标像素的值没有变化
3.2 浮雕效果
浮雕效果,卷积内核
float intensity =2.0f;//
{
intensity * (-2.0f), -intensity, 0.0f,
-intensity, 1.0f, intensity,
0.0f, intensity, intensity * 2.0f,
}
浮雕效果图
浮雕效果接下来的文章,会论述其他通过卷积内核实现的滤镜效果