Skip to content

Commit

Permalink
Added a swirl distortion filter.
Browse files Browse the repository at this point in the history
  • Loading branch information
BradLarson committed Feb 22, 2012
1 parent fe84406 commit 9bf612f
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 2 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,20 @@ For example, an application that takes in live video from the camera, converts t
- *imageWidthFactor*:
- *imageHeightFactor*: These parameters affect the visibility of the detected edges

- **GPUImageSketchFilter**: Converts video to look like a sketch. This is just the Sobel edge detection filter with the colors inverted
- *intensity*: The degree to which the original image colors are replaced by the detected edges (0.0 - 1.0, with 1.0 as the default)
- *imageWidthFactor*:
- *imageHeightFactor*: These parameters affect the visibility of the detected edges

- **GPUImageToonFilter**: This uses Sobel edge detection to place a black border around objects, and then it quantizes the colors present in the image to give a cartoon-like quality to the image.
- *imageWidthFactor*:
- *imageHeightFactor*: These parameters affect the visibility of the detected edges

- **GPUImageSwirlFilter**: Creates a swirl distortion on the image
- *radius*: The radius from the center to apply the distortion, with a default of 0.5
- *center*: The center of the image (in normalized coordinates from 0 - 1.0) about which to twist, with a default of (0.5, 0.5)
- *angle*: The amount of twist to apply to the image, with a default of 1.0

- **GPUImageKuwaharaFilter**: Kuwahara image abstraction, drawn from the work of Kyprianidis, et. al. in their publication "Anisotropic Kuwahara Filtering on the GPU" within the GPU Pro collection. This produces an oil-painting-like image, but it is extremely computationally expensive, so it can take seconds to render a frame on an iPad 2. This might be best used for still images.
- *radius*: In integer specifying the number of pixels out from the center pixel to test when applying the filter, with a default of 4. A higher value creates a more abstracted image, but at the cost of much greater processing time.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
case GPUIMAGE_SOBELEDGEDETECTION: cell.textLabel.text = @"Sobel edge detection"; break;
case GPUIMAGE_SKETCH: cell.textLabel.text = @"Sketch"; break;
case GPUIMAGE_TOON: cell.textLabel.text = @"Toon"; break;
case GPUIMAGE_SWIRL: cell.textLabel.text = @"Swirl"; break;
case GPUIMAGE_DISSOLVE: cell.textLabel.text = @"Dissolve blend"; break;
case GPUIMAGE_MULTIPLY: cell.textLabel.text = @"Multiply blend"; break;
case GPUIMAGE_OVERLAY: cell.textLabel.text = @"Overlay blend"; break;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#import <UIKit/UIKit.h>
#import "GPUImage.h"

typedef enum { GPUIMAGE_SATURATION, GPUIMAGE_CONTRAST, GPUIMAGE_BRIGHTNESS, GPUIMAGE_GAMMA, GPUIMAGE_SEPIA, GPUIMAGE_COLORINVERT, GPUIMAGE_PIXELLATE, GPUIMAGE_SOBELEDGEDETECTION, GPUIMAGE_SKETCH, GPUIMAGE_TOON, GPUIMAGE_KUWAHARA, GPUIMAGE_DISSOLVE, GPUIMAGE_MULTIPLY, GPUIMAGE_OVERLAY, GPUIMAGE_LIGHTEN, GPUIMAGE_DARKEN, GPUIMAGE_CUSTOM, GPUIMAGE_NUMFILTERS} GPUImageShowcaseFilterType;
typedef enum { GPUIMAGE_SATURATION, GPUIMAGE_CONTRAST, GPUIMAGE_BRIGHTNESS, GPUIMAGE_GAMMA, GPUIMAGE_SEPIA, GPUIMAGE_COLORINVERT, GPUIMAGE_PIXELLATE, GPUIMAGE_SOBELEDGEDETECTION, GPUIMAGE_SKETCH, GPUIMAGE_TOON, GPUIMAGE_KUWAHARA, GPUIMAGE_SWIRL, GPUIMAGE_DISSOLVE, GPUIMAGE_MULTIPLY, GPUIMAGE_OVERLAY, GPUIMAGE_LIGHTEN, GPUIMAGE_DARKEN, GPUIMAGE_CUSTOM, GPUIMAGE_NUMFILTERS} GPUImageShowcaseFilterType;

@interface ShowcaseFilterViewController : UIViewController
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,17 @@ - (void)setupFilter;

filter = [[GPUImageToonFilter alloc] init]; break;
};
case GPUIMAGE_SWIRL:
{
self.title = @"Swirl";
self.filterSettingsSlider.hidden = NO;

[self.filterSettingsSlider setMinimumValue:0.0];
[self.filterSettingsSlider setMaximumValue:2.0];
[self.filterSettingsSlider setValue:1.0];

filter = [[GPUImageSwirlFilter alloc] init]; break;
}; break;
case GPUIMAGE_MULTIPLY:
{
self.title = @"Multiply Blend";
Expand Down Expand Up @@ -249,6 +260,7 @@ - (IBAction)updateFilterFromSlider:(id)sender;
case GPUIMAGE_SKETCH: [(GPUImageSketchFilter *)filter setIntensity:[(UISlider *)sender value]]; break;
case GPUIMAGE_DISSOLVE: [(GPUImageDissolveBlendFilter *)filter setMix:[(UISlider *)sender value]]; break;
case GPUIMAGE_KUWAHARA: [(GPUImageKuwaharaFilter *)filter setRadius:round([(UISlider *)sender value])]; break;
case GPUIMAGE_SWIRL: [(GPUImageSwirlFilter *)filter setAngle:[(UISlider *)sender value]]; break;
default: break;
}
}
Expand Down
8 changes: 8 additions & 0 deletions framework/GPUImage.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
BC1B715814F49DAA00ACA2AB /* GPUImageRawData.m in Sources */ = {isa = PBXBuildFile; fileRef = BC1B715614F49DAA00ACA2AB /* GPUImageRawData.m */; };
BC1B717C14F566E200ACA2AB /* GPUImageSketchFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = BC1B717A14F566E200ACA2AB /* GPUImageSketchFilter.h */; };
BC1B717D14F566E200ACA2AB /* GPUImageSketchFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = BC1B717B14F566E200ACA2AB /* GPUImageSketchFilter.m */; };
BC1B718E14F56C1D00ACA2AB /* GPUImageSwirlFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = BC1B718C14F56C1D00ACA2AB /* GPUImageSwirlFilter.h */; };
BC1B718F14F56C1D00ACA2AB /* GPUImageSwirlFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = BC1B718D14F56C1D00ACA2AB /* GPUImageSwirlFilter.m */; };
BC245DC114DDBCF5009FE7EB /* GPUImage.h in Headers */ = {isa = PBXBuildFile; fileRef = BC245DBF14DDBCF5009FE7EB /* GPUImage.h */; };
BC245DCA14DDBED7009FE7EB /* GPUImageFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = BC245DC814DDBED7009FE7EB /* GPUImageFilter.h */; };
BC245DCB14DDBED7009FE7EB /* GPUImageFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = BC245DC914DDBED7009FE7EB /* GPUImageFilter.m */; };
Expand Down Expand Up @@ -93,6 +95,8 @@
BC1B715614F49DAA00ACA2AB /* GPUImageRawData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageRawData.m; path = Source/GPUImageRawData.m; sourceTree = SOURCE_ROOT; };
BC1B717A14F566E200ACA2AB /* GPUImageSketchFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageSketchFilter.h; path = Source/GPUImageSketchFilter.h; sourceTree = SOURCE_ROOT; };
BC1B717B14F566E200ACA2AB /* GPUImageSketchFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageSketchFilter.m; path = Source/GPUImageSketchFilter.m; sourceTree = SOURCE_ROOT; };
BC1B718C14F56C1D00ACA2AB /* GPUImageSwirlFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageSwirlFilter.h; path = Source/GPUImageSwirlFilter.h; sourceTree = SOURCE_ROOT; };
BC1B718D14F56C1D00ACA2AB /* GPUImageSwirlFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageSwirlFilter.m; path = Source/GPUImageSwirlFilter.m; sourceTree = SOURCE_ROOT; };
BC245DBF14DDBCF5009FE7EB /* GPUImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImage.h; path = Source/GPUImage.h; sourceTree = SOURCE_ROOT; };
BC245DC814DDBED7009FE7EB /* GPUImageFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageFilter.h; path = Source/GPUImageFilter.h; sourceTree = SOURCE_ROOT; };
BC245DC914DDBED7009FE7EB /* GPUImageFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageFilter.m; path = Source/GPUImageFilter.m; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -236,6 +240,8 @@
BC1B717B14F566E200ACA2AB /* GPUImageSketchFilter.m */,
BC982C9D14F35C2D0001FF6F /* GPUImageToonFilter.h */,
BC982C9E14F35C2D0001FF6F /* GPUImageToonFilter.m */,
BC1B718C14F56C1D00ACA2AB /* GPUImageSwirlFilter.h */,
BC1B718D14F56C1D00ACA2AB /* GPUImageSwirlFilter.m */,
BC982C4514F29E580001FF6F /* GPUImageKuwaharaFilter.h */,
BC982C4614F29E580001FF6F /* GPUImageKuwaharaFilter.m */,
);
Expand Down Expand Up @@ -394,6 +400,7 @@
BC982C9F14F35C2D0001FF6F /* GPUImageToonFilter.h in Headers */,
BC1B715714F49DAA00ACA2AB /* GPUImageRawData.h in Headers */,
BC1B717C14F566E200ACA2AB /* GPUImageSketchFilter.h in Headers */,
BC1B718E14F56C1D00ACA2AB /* GPUImageSwirlFilter.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -522,6 +529,7 @@
BC982CA014F35C2D0001FF6F /* GPUImageToonFilter.m in Sources */,
BC1B715814F49DAA00ACA2AB /* GPUImageRawData.m in Sources */,
BC1B717D14F566E200ACA2AB /* GPUImageSketchFilter.m in Sources */,
BC1B718F14F56C1D00ACA2AB /* GPUImageSwirlFilter.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
1 change: 1 addition & 0 deletions framework/Source/GPUImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@
#import "GPUImageOverlayBlendFilter.h"
#import "GPUImageDarkenBlendFilter.h"
#import "GPUImageLightenBlendFilter.h"
#import "GPUImageSwirlFilter.h"
2 changes: 1 addition & 1 deletion framework/Source/GPUImageRotationFilter.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
(
varying highp vec2 textureCoordinate;

uniform sampler2D inputImageTexture;\
uniform sampler2D inputImageTexture;

void main()
{
Expand Down
15 changes: 15 additions & 0 deletions framework/Source/GPUImageSwirlFilter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#import "GPUImageFilter.h"

@interface GPUImageSwirlFilter : GPUImageFilter
{
GLint radiusUniform, centerUniform, angleUniform;
}

// The center about which to apply the distortion, with a default of (0.5, 0.5)
@property(readwrite, nonatomic) CGPoint center;
// The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.5
@property(readwrite, nonatomic) CGFloat radius;
// The amount of distortion to apply, with a minimum of 0.0 and a default of 1.0
@property(readwrite, nonatomic) CGFloat angle;

@end
98 changes: 98 additions & 0 deletions framework/Source/GPUImageSwirlFilter.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#import "GPUImageSwirlFilter.h"

// Adapted from the shader example here: http://www.geeks3d.com/20110428/shader-library-swirl-post-processing-filter-in-glsl/

NSString *const kGPUImageSwirlFragmentShaderString = SHADER_STRING
(
varying highp vec2 textureCoordinate;

uniform sampler2D inputImageTexture;

uniform highp vec2 center;
uniform highp float radius;
uniform highp float angle;

void main()
{
highp vec2 textureCoordinateToUse = textureCoordinate;
highp float dist = distance(center, textureCoordinate);
textureCoordinateToUse -= center;
if (dist < radius)
{
highp float percent = (radius - dist) / radius;
// highp float theta = percent * angle;
highp float theta = percent * percent * angle * 8.0;
highp float s = sin(theta);
highp float c = cos(theta);
textureCoordinateToUse = vec2(dot(textureCoordinateToUse, vec2(c, -s)), dot(textureCoordinateToUse, vec2(s, c)));
}
textureCoordinateToUse += center;

gl_FragColor = texture2D(inputImageTexture, textureCoordinateToUse );

}
);

@implementation GPUImageSwirlFilter

#pragma mark -
#pragma mark Initialization and teardown

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

radiusUniform = [filterProgram uniformIndex:@"radius"];
angleUniform = [filterProgram uniformIndex:@"angle"];
centerUniform = [filterProgram uniformIndex:@"center"];

self.radius = 0.5;
self.angle = 1.0;
self.center = CGPointMake(0.5, 0.5);

return self;
}

#pragma mark -
#pragma mark Accessors

@synthesize center = _center;
@synthesize radius = _radius;
@synthesize angle = _angle;

- (void)setRadius:(CGFloat)newValue;
{
_radius = newValue;

[GPUImageOpenGLESContext useImageProcessingContext];
[filterProgram use];
glUniform1f(radiusUniform, _radius);
}

- (void)setAngle:(CGFloat)newValue;
{
_angle = newValue;

[GPUImageOpenGLESContext useImageProcessingContext];
[filterProgram use];
glUniform1f(angleUniform, _angle);
}

- (void)setCenter:(CGPoint)newValue;
{
_center = newValue;

[GPUImageOpenGLESContext useImageProcessingContext];
[filterProgram use];

GLfloat centerPosition[2];
centerPosition[0] = _center.x;
centerPosition[1] = _center.y;

glUniform2fv(centerUniform, 1, centerPosition);
}

@end

0 comments on commit 9bf612f

Please sign in to comment.