Skip to content

Commit

Permalink
Completed the average color filter and created a solid color fill gen…
Browse files Browse the repository at this point in the history
…erator.
  • Loading branch information
BradLarson committed Aug 27, 2012
1 parent 7ca3b66 commit f73c5d8
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 42 deletions.
Expand Up @@ -84,6 +84,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
case GPUIMAGE_HIGHLIGHTSHADOW: cell.textLabel.text = @"Highlights and shadows"; break;
case GPUIMAGE_HAZE: cell.textLabel.text = @"Haze"; break;
case GPUIMAGE_HISTOGRAM: cell.textLabel.text = @"Histogram"; break;
case GPUIMAGE_AVERAGECOLOR: cell.textLabel.text = @"Average color"; break;
case GPUIMAGE_THRESHOLD: cell.textLabel.text = @"Threshold"; break;
case GPUIMAGE_ADAPTIVETHRESHOLD: cell.textLabel.text = @"Adaptive threshold"; break;
case GPUIMAGE_CROP: cell.textLabel.text = @"Crop"; break;
Expand Down
Expand Up @@ -27,6 +27,7 @@ typedef enum {
GPUIMAGE_COLORINVERT,
GPUIMAGE_GRAYSCALE,
GPUIMAGE_HISTOGRAM,
GPUIMAGE_AVERAGECOLOR,
GPUIMAGE_THRESHOLD,
GPUIMAGE_ADAPTIVETHRESHOLD,
GPUIMAGE_PIXELLATE,
Expand Down
Expand Up @@ -311,6 +311,13 @@ - (void)setupFilter;
[self.filterSettingsSlider setValue:0.2];

filter = [[GPUImageHazeFilter alloc] init];
}; break;
case GPUIMAGE_AVERAGECOLOR:
{
self.title = @"Average Color";
self.filterSettingsSlider.hidden = YES;

filter = [[GPUImageAverageColor alloc] init];
}; break;
case GPUIMAGE_HISTOGRAM:
{
Expand Down Expand Up @@ -1169,10 +1176,21 @@ - (void)setupFilter;
[blendFilter addTarget:filterView];

}
else if (filterType == GPUIMAGE_AVERAGECOLOR)
{
GPUImageSolidColorGenerator *colorGenerator = [[GPUImageSolidColorGenerator alloc] init];
[colorGenerator forceProcessingAtSize:[filterView sizeInPixels]];

[(GPUImageAverageColor *)filter setColorAverageProcessingFinishedBlock:^(CGFloat redComponent, CGFloat greenComponent, CGFloat blueComponent, CGFloat alphaComponent, CMTime frameTime) {
[colorGenerator setColorRed:redComponent green:greenComponent blue:blueComponent alpha:alphaComponent];
// NSLog(@"Average color: %f, %f, %f, %f", redComponent, greenComponent, blueComponent, alphaComponent);
}];

[colorGenerator addTarget:filterView];
}
else
{
[filter addTarget:filterView];

}
}

Expand Down
8 changes: 8 additions & 0 deletions framework/GPUImage.xcodeproj/project.pbxproj
Expand Up @@ -202,6 +202,8 @@
BCB6B8BC1505BF940041703B /* GPUImageTextureOutput.m in Sources */ = {isa = PBXBuildFile; fileRef = BCB6B8BA1505BF940041703B /* GPUImageTextureOutput.m */; };
BCB6B9041507CA8D0041703B /* GPUImageCropFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = BCB6B9021507CA8C0041703B /* GPUImageCropFilter.h */; };
BCB6B9051507CA8D0041703B /* GPUImageCropFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = BCB6B9031507CA8C0041703B /* GPUImageCropFilter.m */; };
BCB79E1015EBE1A700965D92 /* GPUImageSolidColorGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = BCB79E0E15EBE1A600965D92 /* GPUImageSolidColorGenerator.h */; };
BCB79E1115EBE1A700965D92 /* GPUImageSolidColorGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = BCB79E0F15EBE1A600965D92 /* GPUImageSolidColorGenerator.m */; };
BCBCE9991595021B00E0ED33 /* GPUImageMonochromeFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = BCBCE9971595021B00E0ED33 /* GPUImageMonochromeFilter.h */; };
BCBCE99A1595021B00E0ED33 /* GPUImageMonochromeFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = BCBCE9981595021B00E0ED33 /* GPUImageMonochromeFilter.m */; };
BCBCE9D5159944AC00E0ED33 /* GPUImageBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = BCBCE9D3159944AB00E0ED33 /* GPUImageBuffer.h */; };
Expand Down Expand Up @@ -486,6 +488,8 @@
BCB6B8BA1505BF940041703B /* GPUImageTextureOutput.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageTextureOutput.m; path = Source/GPUImageTextureOutput.m; sourceTree = SOURCE_ROOT; };
BCB6B9021507CA8C0041703B /* GPUImageCropFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageCropFilter.h; path = Source/GPUImageCropFilter.h; sourceTree = SOURCE_ROOT; };
BCB6B9031507CA8C0041703B /* GPUImageCropFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageCropFilter.m; path = Source/GPUImageCropFilter.m; sourceTree = SOURCE_ROOT; };
BCB79E0E15EBE1A600965D92 /* GPUImageSolidColorGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageSolidColorGenerator.h; path = Source/GPUImageSolidColorGenerator.h; sourceTree = SOURCE_ROOT; };
BCB79E0F15EBE1A600965D92 /* GPUImageSolidColorGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageSolidColorGenerator.m; path = Source/GPUImageSolidColorGenerator.m; sourceTree = SOURCE_ROOT; };
BCBCE9971595021B00E0ED33 /* GPUImageMonochromeFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageMonochromeFilter.h; path = Source/GPUImageMonochromeFilter.h; sourceTree = SOURCE_ROOT; };
BCBCE9981595021B00E0ED33 /* GPUImageMonochromeFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageMonochromeFilter.m; path = Source/GPUImageMonochromeFilter.m; sourceTree = SOURCE_ROOT; };
BCBCE9D3159944AB00E0ED33 /* GPUImageBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageBuffer.h; path = Source/GPUImageBuffer.h; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -665,6 +669,8 @@
BCF6B41015A7849F00FC6F58 /* GPUImageOpacityFilter.m */,
BC3AC8AE15E6F6170065144E /* GPUImageAverageColor.h */,
BC3AC8AF15E6F6170065144E /* GPUImageAverageColor.m */,
BCB79E0E15EBE1A600965D92 /* GPUImageSolidColorGenerator.h */,
BCB79E0F15EBE1A600965D92 /* GPUImageSolidColorGenerator.m */,
);
name = "Color processing";
sourceTree = "<group>";
Expand Down Expand Up @@ -1124,6 +1130,7 @@
BCF851BF15CF5D59000EBC8B /* GPUImageLocalBinaryPatternFilter.h in Headers */,
BCFB588715E03E4F00750F12 /* GPUImageLanczosResamplingFilter.h in Headers */,
BC3AC8B015E6F6170065144E /* GPUImageAverageColor.h in Headers */,
BCB79E1015EBE1A700965D92 /* GPUImageSolidColorGenerator.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1366,6 +1373,7 @@
BCF851C015CF5D59000EBC8B /* GPUImageLocalBinaryPatternFilter.m in Sources */,
BCFB588815E03E4F00750F12 /* GPUImageLanczosResamplingFilter.m in Sources */,
BC3AC8B115E6F6170065144E /* GPUImageAverageColor.m in Sources */,
BCB79E1115EBE1A700965D92 /* GPUImageSolidColorGenerator.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
3 changes: 2 additions & 1 deletion framework/Source/GPUImage.h
Expand Up @@ -119,4 +119,5 @@
#import "GPUImagePolkaDotFilter.h"
#import "GPUImageLocalBinaryPatternFilter.h"
#import "GPUImageLanczosResamplingFilter.h"
#import "GPUImageAverageColor.h"
#import "GPUImageAverageColor.h"
#import "GPUImageSolidColorGenerator.h"
84 changes: 44 additions & 40 deletions framework/Source/GPUImageAverageColor.m
Expand Up @@ -96,14 +96,19 @@ - (void)initializeOutputTexture;

NSUInteger numberOfReductionsInX = floor(log(inputTextureSize.width) / log(4.0));
NSUInteger numberOfReductionsInY = floor(log(inputTextureSize.height) / log(4.0));
NSLog(@"Reductions in X: %d, y: %d", numberOfReductionsInX, numberOfReductionsInY);
// NSLog(@"Reductions in X: %d, y: %d", numberOfReductionsInX, numberOfReductionsInY);

NSUInteger reductionsToHitSideLimit = MIN(numberOfReductionsInX, numberOfReductionsInY);
NSLog(@"Total reductions: %d", reductionsToHitSideLimit);
// NSLog(@"Total reductions: %d", reductionsToHitSideLimit);
for (NSUInteger currentReduction = 0; currentReduction < reductionsToHitSideLimit; currentReduction++)
{
// CGSize currentStageSize = CGSizeMake(ceil(inputTextureSize.width / pow(4.0, currentReduction + 1.0)), ceil(inputTextureSize.height / pow(4.0, currentReduction + 1.0)));
CGSize currentStageSize = CGSizeMake(floor(inputTextureSize.width / pow(4.0, currentReduction + 1.0)), floor(inputTextureSize.height / pow(4.0, currentReduction + 1.0)));
if (currentStageSize.height < 2.0)
{
currentStageSize.height = 2.0; // TODO: Rotate the image to account for this case, which causes FBO construction to fail
}

[stageSizes addObject:[NSValue valueWithCGSize:currentStageSize]];

GLuint textureForStage;
Expand All @@ -115,7 +120,7 @@ - (void)initializeOutputTexture;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
[stageTextures addObject:[NSNumber numberWithInt:textureForStage]];

NSLog(@"At reduction: %d size in X: %f, size in Y:%f", currentReduction, currentStageSize.width, currentStageSize.height);
// NSLog(@"At reduction: %d size in X: %f, size in Y:%f", currentReduction, currentStageSize.width, currentStageSize.height);
}
});
}
Expand Down Expand Up @@ -163,7 +168,6 @@ - (void)createFilterFBOofSize:(CGSize)currentFBOSize;
glActiveTexture(GL_TEXTURE1);

NSUInteger numberOfStageFramebuffers = [stageTextures count];
NSLog(@"Number of stages: %d", numberOfStageFramebuffers);
for (NSUInteger currentStage = 0; currentStage < numberOfStageFramebuffers; currentStage++)
{
GLuint currentFramebuffer;
Expand All @@ -176,12 +180,12 @@ - (void)createFilterFBOofSize:(CGSize)currentFBOSize;

CGSize currentFramebufferSize = [[stageSizes objectAtIndex:currentStage] CGSizeValue];

NSLog(@"FBO stage size: %f, %f", currentFramebufferSize.width, currentFramebufferSize.height);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)currentFramebufferSize.width, (int)currentFramebufferSize.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, currentTexture, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

NSAssert(status == GL_FRAMEBUFFER_COMPLETE, @"Incomplete filter FBO: %d", status);
NSLog(@"Constructing framebuffer at index: %d of size: %f, %f", currentStage, currentFramebufferSize.width, currentFramebufferSize.height);
}
});

Expand Down Expand Up @@ -241,42 +245,42 @@ - (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

currentTexture = [[stageTextures objectAtIndex:currentStage] intValue];

NSUInteger totalBytesForImage = (int)currentStageSize.width * (int)currentStageSize.height * 4;
GLubyte *rawImagePixels2 = (GLubyte *)malloc(totalBytesForImage);
glReadPixels(0, 0, (int)currentStageSize.width, (int)currentStageSize.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels2);
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, rawImagePixels2, totalBytesForImage, NULL);
CGColorSpaceRef defaultRGBColorSpace = CGColorSpaceCreateDeviceRGB();

CGFloat currentRedTotal = 0.0f, currentGreenTotal = 0.0f, currentBlueTotal = 0.0f, currentAlphaTotal = 0.0f;
NSUInteger totalNumberOfPixels = totalBytesForImage / 4;

for (NSUInteger currentPixel = 0; currentPixel < totalNumberOfPixels; currentPixel++)
{
currentRedTotal += (CGFloat)rawImagePixels2[(currentPixel * 4)] / 255.0f;
currentGreenTotal += (CGFloat)rawImagePixels2[(currentPixel * 4) + 1] / 255.0f;
currentBlueTotal += (CGFloat)rawImagePixels2[(currentPixel * 4 + 2)] / 255.0f;
currentAlphaTotal += (CGFloat)rawImagePixels2[(currentPixel * 4) + 3] / 255.0f;
}

NSLog(@"Stage %d average image red: %f, green: %f, blue: %f, alpha: %f", currentStage, currentRedTotal / (CGFloat)totalNumberOfPixels, currentGreenTotal / (CGFloat)totalNumberOfPixels, currentBlueTotal / (CGFloat)totalNumberOfPixels, currentAlphaTotal / (CGFloat)totalNumberOfPixels);


CGImageRef cgImageFromBytes = CGImageCreate((int)currentStageSize.width, (int)currentStageSize.height, 8, 32, 4 * (int)currentStageSize.width, defaultRGBColorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaLast, dataProvider, NULL, NO, kCGRenderingIntentDefault);

UIImage *imageToSave = [UIImage imageWithCGImage:cgImageFromBytes];

NSData *dataForPNGFile = UIImagePNGRepresentation(imageToSave);

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

NSString *imageName = [NSString stringWithFormat:@"AverageLevel%d.png", currentStage];
NSError *error = nil;
if (![dataForPNGFile writeToFile:[documentsDirectory stringByAppendingPathComponent:imageName] options:NSAtomicWrite error:&error])
{
return;
}
// NSUInteger totalBytesForImage = (int)currentStageSize.width * (int)currentStageSize.height * 4;
// GLubyte *rawImagePixels2 = (GLubyte *)malloc(totalBytesForImage);
// glReadPixels(0, 0, (int)currentStageSize.width, (int)currentStageSize.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels2);
// CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, rawImagePixels2, totalBytesForImage, NULL);
// CGColorSpaceRef defaultRGBColorSpace = CGColorSpaceCreateDeviceRGB();
//
// CGFloat currentRedTotal = 0.0f, currentGreenTotal = 0.0f, currentBlueTotal = 0.0f, currentAlphaTotal = 0.0f;
// NSUInteger totalNumberOfPixels = totalBytesForImage / 4;
//
// for (NSUInteger currentPixel = 0; currentPixel < totalNumberOfPixels; currentPixel++)
// {
// currentRedTotal += (CGFloat)rawImagePixels2[(currentPixel * 4)] / 255.0f;
// currentGreenTotal += (CGFloat)rawImagePixels2[(currentPixel * 4) + 1] / 255.0f;
// currentBlueTotal += (CGFloat)rawImagePixels2[(currentPixel * 4 + 2)] / 255.0f;
// currentAlphaTotal += (CGFloat)rawImagePixels2[(currentPixel * 4) + 3] / 255.0f;
// }
//
// NSLog(@"Stage %d average image red: %f, green: %f, blue: %f, alpha: %f", currentStage, currentRedTotal / (CGFloat)totalNumberOfPixels, currentGreenTotal / (CGFloat)totalNumberOfPixels, currentBlueTotal / (CGFloat)totalNumberOfPixels, currentAlphaTotal / (CGFloat)totalNumberOfPixels);
//
//
// CGImageRef cgImageFromBytes = CGImageCreate((int)currentStageSize.width, (int)currentStageSize.height, 8, 32, 4 * (int)currentStageSize.width, defaultRGBColorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaLast, dataProvider, NULL, NO, kCGRenderingIntentDefault);
//
// UIImage *imageToSave = [UIImage imageWithCGImage:cgImageFromBytes];
//
// NSData *dataForPNGFile = UIImagePNGRepresentation(imageToSave);
//
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// NSString *documentsDirectory = [paths objectAtIndex:0];
//
// NSString *imageName = [NSString stringWithFormat:@"AverageLevel%d.png", currentStage];
// NSError *error = nil;
// if (![dataForPNGFile writeToFile:[documentsDirectory stringByAppendingPathComponent:imageName] options:NSAtomicWrite error:&error])
// {
// return;
// }
}
}

Expand Down
17 changes: 17 additions & 0 deletions framework/Source/GPUImageSolidColorGenerator.h
@@ -0,0 +1,17 @@
#import "GPUImageFilter.h"

// This outputs an image with a constant color. You need to use -forceProcessingAtSize: in order to set the output image
// dimensions, or this won't work correctly


@interface GPUImageSolidColorGenerator : GPUImageFilter
{
GLint colorUniform;
}

// This color dictates what the output image will be filled with
@property(readwrite, nonatomic) GPUVector4 color;

- (void)setColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent;

@end
81 changes: 81 additions & 0 deletions framework/Source/GPUImageSolidColorGenerator.m
@@ -0,0 +1,81 @@
#import "GPUImageSolidColorGenerator.h"

NSString *const kGPUSolidColorFragmentShaderString = SHADER_STRING
(
precision lowp float;

varying highp vec2 textureCoordinate;

uniform sampler2D inputImageTexture;
uniform vec4 color;

void main()
{
gl_FragColor = color;
}
);

@implementation GPUImageSolidColorGenerator

@synthesize color = _color;

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

colorUniform = [filterProgram uniformIndex:@"color"];

self.color = (GPUVector4){0.0f, 0.0f, 0.5f, 1.0f};

return self;
}


#pragma mark -
#pragma mark Accessors

- (void)forceProcessingAtSize:(CGSize)frameSize;
{
[super forceProcessingAtSize:frameSize];

if (!CGSizeEqualToSize(inputTextureSize, CGSizeZero))
{
[self newFrameReadyAtTime:kCMTimeIndefinite atIndex:0];
}
}

- (void)addTarget:(id<GPUImageInput>)newTarget atTextureLocation:(NSInteger)textureLocation;
{
[super addTarget:newTarget atTextureLocation:textureLocation];

if (!CGSizeEqualToSize(inputTextureSize, CGSizeZero))
{
[newTarget setInputSize:inputTextureSize atIndex:textureLocation];
[newTarget newFrameReadyAtTime:kCMTimeIndefinite atIndex:textureLocation];
}
}

- (void)setColor:(GPUVector4)newValue;
{
[self setColorRed:_color.one green:_color.two blue:_color.three alpha:_color.four];
}

- (void)setColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent;
{
_color.one = redComponent;
_color.two = greenComponent;
_color.three = blueComponent;
_color.four = alphaComponent;

[self setVec4:_color forUniform:colorUniform program:filterProgram];

if (!CGSizeEqualToSize(inputTextureSize, CGSizeZero))
{
[self newFrameReadyAtTime:kCMTimeIndefinite atIndex:0];
}
}

@end

0 comments on commit f73c5d8

Please sign in to comment.