GPUImageBilateralFilter是双边滤波,它和高斯滤波类似,也是一种加权平均,但可以保持图像中的边缘。原理网上有很多,简单说下自己的理解。高斯滤波的权重是基于采样点与中心点的距离决定,采样点离中心点越近,权重越大,而双边滤波的权重不仅考虑了距离,还考虑采样点与中心点像素颜色的相似程度,采样点与中心点像素越相似,权重也越高,相反差别越大权重越低,这样可以防止在像素变化剧烈的地方(也就是图像中的边缘)被平滑掉。
GPUImageBilateralFilter继承自GPUImageGaussianBlurFilter,它和高斯滤波很相似,同样进行一次行滤波,一次列滤波,只是着色器的实现不同。这里只分析写它的着色器实现。顶点着色器代码如下:
NSString *const kGPUImageBilateralBlurVertexShaderString = SHADER_STRING
(
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
const int GAUSSIAN_SAMPLES = 9;
uniform float texelWidthOffset;
uniform float texelHeightOffset;
varying vec2 textureCoordinate;
varying vec2 blurCoordinates[GAUSSIAN_SAMPLES];
void main()
{
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy;
// Calculate the positions for the blur
int multiplier = 0;
vec2 blurStep;
//第一个编译器,进行的是行滤波,因此texelWidthOffset=1/width,texelHeightOffset=0
//对于第二个编译器,进行的是列滤波,因此texelWidthOffset=0,texelHeightOffset=1/height
//(width, height是原图像的宽和高)
vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);
//求出采样点的坐标值
for (int i = 0; i < GAUSSIAN_SAMPLES; i++)
{
multiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2)); //multiplier为-4,-3,-2,-1,0,1,2,3,4
// Blur in x (horizontal)
blurStep = float(multiplier) * singleStepOffset;
blurCoordinates[i] = inputTextureCoordinate.xy + blurStep;
}
}
);
片元着色器代码为:
NSString *const kGPUImageBilateralFilterFragmentShaderString = SHADER_STRING
(
uniform sampler2D inputImageTexture;
const lowp int GAUSSIAN_SAMPLES = 9;
varying highp vec2 textureCoordinate;
varying highp vec2 blurCoordinates[GAUSSIAN_SAMPLES];
uniform mediump float distanceNormalizationFactor;
void main()
{
lowp vec4 centralColor;
lowp float gaussianWeightTotal;
lowp vec4 sum;
lowp vec4 sampleColor;
lowp float distanceFromCentralColor;
lowp float gaussianWeight;
centralColor = texture2D(inputImageTexture, blurCoordinates[4]);
gaussianWeightTotal = 0.18;
sum = centralColor * 0.18;
//采样点颜色
sampleColor = texture2D(inputImageTexture, blurCoordinates[0]);
//计算采样点与中心点的颜色差距,最大值为1
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
//distanceFromCentralColor越大,gaussianWeight越小
gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);
gaussianWeightTotal += gaussianWeight;
sum += sampleColor * gaussianWeight;
//下面同理
sampleColor = texture2D(inputImageTexture, blurCoordinates[1]);
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor);
gaussianWeightTotal += gaussianWeight;
sum += sampleColor * gaussianWeight;
sampleColor = texture2D(inputImageTexture, blurCoordinates[2]);
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor);
gaussianWeightTotal += gaussianWeight;
sum += sampleColor * gaussianWeight;
sampleColor = texture2D(inputImageTexture, blurCoordinates[3]);
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor);
gaussianWeightTotal += gaussianWeight;
sum += sampleColor * gaussianWeight;
sampleColor = texture2D(inputImageTexture, blurCoordinates[5]);
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor);
gaussianWeightTotal += gaussianWeight;
sum += sampleColor * gaussianWeight;
sampleColor = texture2D(inputImageTexture, blurCoordinates[6]);
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor);
gaussianWeightTotal += gaussianWeight;
sum += sampleColor * gaussianWeight;
sampleColor = texture2D(inputImageTexture, blurCoordinates[7]);
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor);
gaussianWeightTotal += gaussianWeight;
sum += sampleColor * gaussianWeight;
sampleColor = texture2D(inputImageTexture, blurCoordinates[8]);
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);
gaussianWeightTotal += gaussianWeight;
sum += sampleColor * gaussianWeight;
gl_FragColor = sum / gaussianWeightTotal;
}
);
着色器代码也挺简单的,顶点着色器主要计算采样点的坐标,片元着色器中,以高斯滤波的权重为基础(0.05,0.09,0.12,0.15,0.18),乘以采样点与中心点颜色差别因子,得到最终的滤波权重。
网友评论