#import "GPUImageBilateralFilter.h"
|
|
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;
|
vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);
|
|
for (int i = 0; i < GAUSSIAN_SAMPLES; i++)
|
{
|
multiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2));
|
// Blur in x (horizontal)
|
blurStep = float(multiplier) * singleStepOffset;
|
blurCoordinates[i] = inputTextureCoordinate.xy + blurStep;
|
}
|
}
|
);
|
|
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
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]);
|
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
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;
|
}
|
);
|
#else
|
NSString *const kGPUImageBilateralFilterFragmentShaderString = SHADER_STRING
|
(
|
uniform sampler2D inputImageTexture;
|
|
const int GAUSSIAN_SAMPLES = 9;
|
|
varying vec2 textureCoordinate;
|
varying vec2 blurCoordinates[GAUSSIAN_SAMPLES];
|
|
uniform float distanceNormalizationFactor;
|
|
void main()
|
{
|
vec4 centralColor;
|
float gaussianWeightTotal;
|
vec4 sum;
|
vec4 sampleColor;
|
float distanceFromCentralColor;
|
float gaussianWeight;
|
|
centralColor = texture2D(inputImageTexture, blurCoordinates[4]);
|
gaussianWeightTotal = 0.18;
|
sum = centralColor * 0.18;
|
|
sampleColor = texture2D(inputImageTexture, blurCoordinates[0]);
|
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
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;
|
}
|
);
|
#endif
|
|
@implementation GPUImageBilateralFilter
|
|
@synthesize distanceNormalizationFactor = _distanceNormalizationFactor;
|
|
- (id)init;
|
{
|
|
if (!(self = [super initWithFirstStageVertexShaderFromString:kGPUImageBilateralBlurVertexShaderString
|
firstStageFragmentShaderFromString:kGPUImageBilateralFilterFragmentShaderString
|
secondStageVertexShaderFromString:kGPUImageBilateralBlurVertexShaderString
|
secondStageFragmentShaderFromString:kGPUImageBilateralFilterFragmentShaderString])) {
|
return nil;
|
}
|
|
firstDistanceNormalizationFactorUniform = [filterProgram uniformIndex:@"distanceNormalizationFactor"];
|
secondDistanceNormalizationFactorUniform = [filterProgram uniformIndex:@"distanceNormalizationFactor"];
|
|
self.texelSpacingMultiplier = 4.0;
|
self.distanceNormalizationFactor = 8.0;
|
|
|
return self;
|
}
|
|
|
#pragma mark -
|
#pragma mark Accessors
|
|
- (void)setDistanceNormalizationFactor:(CGFloat)newValue
|
{
|
_distanceNormalizationFactor = newValue;
|
|
[self setFloat:newValue
|
forUniform:firstDistanceNormalizationFactorUniform
|
program:filterProgram];
|
|
[self setFloat:newValue
|
forUniform:secondDistanceNormalizationFactorUniform
|
program:secondFilterProgram];
|
}
|
|
@end
|