Skip to content

Commit

Permalink
Added a hue adjustment filter.
Browse files Browse the repository at this point in the history
  • Loading branch information
Cameron committed Jul 21, 2012
1 parent 8c351ac commit 6566040
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 1 deletion.
Expand Up @@ -7,6 +7,7 @@ typedef enum {
GPUIMAGE_BRIGHTNESS,
GPUIMAGE_EXPOSURE,
GPUIMAGE_RGB,
GPUIMAGE_HUE,
GPUIMAGE_MONOCHROME,
GPUIMAGE_FALSECOLOR,
GPUIMAGE_SHARPEN,
Expand Down
Expand Up @@ -179,6 +179,17 @@ - (void)setupFilter;

filter = [[GPUImageRGBFilter alloc] init];
}; break;
case GPUIMAGE_HUE:
{
self.title = @"Hue";
self.filterSettingsSlider.hidden = NO;

[self.filterSettingsSlider setMinimumValue:0.0];
[self.filterSettingsSlider setMaximumValue:360.0];
[self.filterSettingsSlider setValue:90.0];

filter = [[GPUImageHueFilter alloc] init];
}; break;
case GPUIMAGE_EXPOSURE:
{
self.title = @"Exposure";
Expand Down Expand Up @@ -1085,6 +1096,7 @@ - (IBAction)updateFilterFromSlider:(id)sender;
case GPUIMAGE_EXPOSURE: [(GPUImageExposureFilter *)filter setExposure:[(UISlider *)sender value]]; break;
case GPUIMAGE_MONOCHROME: [(GPUImageMonochromeFilter *)filter setIntensity:[(UISlider *)sender value]]; break;
case GPUIMAGE_RGB: [(GPUImageRGBFilter *)filter setGreen:[(UISlider *)sender value]]; break;
case GPUIMAGE_HUE: [(GPUImageHueFilter *)filter setHue:90.0]; break;
case GPUIMAGE_SHARPEN: [(GPUImageSharpenFilter *)filter setSharpness:[(UISlider *)sender value]]; break;
case GPUIMAGE_HISTOGRAM: [(GPUImageHistogramFilter *)filter setDownsamplingFactor:round([(UISlider *)sender value])]; break;
case GPUIMAGE_UNSHARPMASK: [(GPUImageUnsharpMaskFilter *)filter setIntensity:[(UISlider *)sender value]]; break;
Expand Down
8 changes: 8 additions & 0 deletions framework/GPUImage.xcodeproj/project.pbxproj
Expand Up @@ -262,6 +262,8 @@
BCF6B41215A7849F00FC6F58 /* GPUImageOpacityFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = BCF6B41015A7849F00FC6F58 /* GPUImageOpacityFilter.m */; };
BEBE83B5155C092A00EEF8C3 /* GPUImageRGBFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = BEBE83B3155C092A00EEF8C3 /* GPUImageRGBFilter.h */; };
BEBE83B6155C092A00EEF8C3 /* GPUImageRGBFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = BEBE83B4155C092A00EEF8C3 /* GPUImageRGBFilter.m */; };
C2EDA90615BB136D007CBA0F /* GPUImageHueFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EDA90415BB136D007CBA0F /* GPUImageHueFilter.h */; };
C2EDA90715BB136D007CBA0F /* GPUImageHueFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = C2EDA90515BB136D007CBA0F /* GPUImageHueFilter.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -519,6 +521,8 @@
BCF6B41015A7849F00FC6F58 /* GPUImageOpacityFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageOpacityFilter.m; path = Source/GPUImageOpacityFilter.m; sourceTree = SOURCE_ROOT; };
BEBE83B3155C092A00EEF8C3 /* GPUImageRGBFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageRGBFilter.h; path = Source/GPUImageRGBFilter.h; sourceTree = SOURCE_ROOT; };
BEBE83B4155C092A00EEF8C3 /* GPUImageRGBFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageRGBFilter.m; path = Source/GPUImageRGBFilter.m; sourceTree = SOURCE_ROOT; };
C2EDA90415BB136D007CBA0F /* GPUImageHueFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageHueFilter.h; path = Source/GPUImageHueFilter.h; sourceTree = SOURCE_ROOT; };
C2EDA90515BB136D007CBA0F /* GPUImageHueFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageHueFilter.m; path = Source/GPUImageHueFilter.m; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -574,6 +578,8 @@
B81521A014F1BA6A00F105F8 /* GPUImageColorMatrixFilter.h */,
B81521A114F1BA6A00F105F8 /* GPUImageColorMatrixFilter.m */,
BEBE83B3155C092A00EEF8C3 /* GPUImageRGBFilter.h */,
C2EDA90415BB136D007CBA0F /* GPUImageHueFilter.h */,
C2EDA90515BB136D007CBA0F /* GPUImageHueFilter.m */,
BEBE83B4155C092A00EEF8C3 /* GPUImageRGBFilter.m */,
BCC46E5C15B9EFE8005519B9 /* GPUImageHighlightShadowFilter.h */,
BCC46E5D15B9EFE8005519B9 /* GPUImageHighlightShadowFilter.m */,
Expand Down Expand Up @@ -1033,6 +1039,7 @@
BCF6B41115A7849F00FC6F58 /* GPUImageOpacityFilter.h in Headers */,
BCC46E5E15B9EFE8005519B9 /* GPUImageHighlightShadowFilter.h in Headers */,
BCC46E6315BA095F005519B9 /* GPUImageFalseColorFilter.h in Headers */,
C2EDA90615BB136D007CBA0F /* GPUImageHueFilter.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1262,6 +1269,7 @@
BCF6B41215A7849F00FC6F58 /* GPUImageOpacityFilter.m in Sources */,
BCC46E5F15B9EFE8005519B9 /* GPUImageHighlightShadowFilter.m in Sources */,
BCC46E6415BA095F005519B9 /* GPUImageFalseColorFilter.m in Sources */,
C2EDA90715BB136D007CBA0F /* GPUImageHueFilter.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
3 changes: 2 additions & 1 deletion framework/Source/GPUImage.h
Expand Up @@ -106,4 +106,5 @@
#import "GPUImageMonochromeFilter.h"
#import "GPUImageOpacityFilter.h"
#import "GPUImageHighlightShadowFilter.h"
#import "GPUImageFalseColorFilter.h"
#import "GPUImageFalseColorFilter.h"
#import "GPUImageHueFilter.h"
11 changes: 11 additions & 0 deletions framework/Source/GPUImageHueFilter.h
@@ -0,0 +1,11 @@

#import "GPUImageFilter.h"

@interface GPUImageHueFilter : GPUImageFilter
{
GLfloat hueAdjustUniform;

}
@property (nonatomic, readwrite) CGFloat hue;

@end
76 changes: 76 additions & 0 deletions framework/Source/GPUImageHueFilter.m
@@ -0,0 +1,76 @@

#import "GPUImageHueFilter.h"

// Adapted from http://stackoverflow.com/questions/9234724/how-to-change-hue-of-a-texture-with-glsl - see for code and discussion
NSString *const kGPUImageHueFragmentShaderString = SHADER_STRING
(
precision highp float;
varying highp vec2 textureCoordinate;

uniform sampler2D inputImageTexture;
uniform mediump float hueAdjust;
const highp vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);
const highp vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);
const highp vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);

const highp vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);
const highp vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);
const highp vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);

void main ()
{
// Sample the input pixel
highp vec4 color = texture2D(inputImageTexture, textureCoordinate);

// Convert to YIQ
highp float YPrime = dot (color, kRGBToYPrime);
highp float I = dot (color, kRGBToI);
highp float Q = dot (color, kRGBToQ);

// Calculate the hue and chroma
highp float hue = atan (Q, I);
highp float chroma = sqrt (I * I + Q * Q);

// Make the user's adjustments
hue += (-hueAdjust); //why negative rotation?

// Convert back to YIQ
Q = chroma * sin (hue);
I = chroma * cos (hue);

// Convert back to RGB
highp vec4 yIQ = vec4 (YPrime, I, Q, 0.0);
color.r = dot (yIQ, kYIQToR);
color.g = dot (yIQ, kYIQToG);
color.b = dot (yIQ, kYIQToB);

// Save the result
gl_FragColor = color;
}
);


@implementation GPUImageHueFilter
@synthesize hue;

-(id) init {
if(! (self = [super initWithFragmentShaderFromString:kGPUImageHueFragmentShaderString]) ){
return nil;
}

hueAdjustUniform = [filterProgram uniformIndex:@"hueAdjust"];
self.hue = 90;

return self;
}

-(void) setHue:(CGFloat)newHue {
hue = fmodf(newHue, 360.0);
[GPUImageOpenGLESContext useImageProcessingContext];
[filterProgram use];
glUniform1f(hueAdjustUniform, hue);

}


@end

0 comments on commit 6566040

Please sign in to comment.