Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to effect an image with multiple core image filters (without resetting the result)

I have a project with several core image filters, each connected to a different slider. Everything works but I just have not figured out the best way to pass the results from one filter to the next. They each reset each time I change any of the other sliders. The reason is because the original image, created from an imported image is drawn in by each filter as the input image. But not sure how to fix this.

I am trying to think of the best way to pass in the results of multiple filters into one output image.

here is the project: owolf.net/uploads/StackOverflow/CoreImageFilter.zip

and some of the viewControler's code pasted below:

- (void)viewDidLoad
{
    //Create CIImage
    UIImage *aUIImage = [imageView image];
    CGImageRef aCGImage = aUIImage.CGImage;
    aCIImage = [CIImage imageWithCGImage:aCGImage];

    //Create context
    context = [CIContext contextWithOptions:nil];

    saturationFilter = [CIFilter filterWithName:@"CIColorControls" keysAndValues: @"inputImage", aCIImage, nil];
    brightnessFilter = [CIFilter filterWithName:@"CIColorControls" keysAndValues: @"inputImage", aCIImage, nil];
    contrastFilter = [CIFilter filterWithName:@"CIColorControls" keysAndValues: @"inputImage", aCIImage, nil];
        [super viewDidLoad];
}


- (IBAction)saturationSliderValueChanged:(id)sender {
    outputImage = [saturationFilter outputImage];
    CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
    newUIImage = [UIImage imageWithCGImage:cgimg];
    CGImageRelease(cgimg);
    [imageView setImage:newUIImage];   
}

- (IBAction)brightnessSliderValueChanged:(id)sender {
    [brightnessFilter setValue:[NSNumber numberWithFloat:brigtnessSlider.value] forKey: @"inputBrightness"];
    outputImage = [brightnessFilter outputImage];
    CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
    newUIImage = [UIImage imageWithCGImage:cgimg];
    CGImageRelease(cgimg);
    [imageView setImage:newUIImage];
}

- (IBAction)contrastSliderValueChanged:(id)sender { 
    [contrastFilter setValue:[NSNumber numberWithFloat:contrastSlider.value] forKey: @"inputContrast"];
    outputImage = [contrastFilter outputImage];
    CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
    newUIImage = [UIImage imageWithCGImage:cgimg];
    CGImageRelease(cgimg);
    [imageView setImage:newUIImage];
}
like image 762
Mr Ordinary Avatar asked Aug 13 '12 04:08

Mr Ordinary


2 Answers

You need to choose an order in which to apply the filters, then use the output of the first filter as the input image of the second, and so on. Here's an example from one of my projects:

CIImage *adjustedImage = self.originalImage;

[self.vibranceFilter setValue:adjustedImage forKey:@"inputImage"];
adjustedImage = [self.vibranceFilter outputImage];

[self.hueFilter setValue:adjustedImage forKey:@"inputImage"];
adjustedImage = [self.hueFilter outputImage];

[self.vignetteFilter setValue:adjustedImage forKey:@"inputImage"];
adjustedImage = [self.vignetteFilter outputImage];

CGImageRef cgImage = [self.imageContext createCGImage:adjustedImage fromRect:[adjustedImage extent]];

self.imageView.image = [UIImage imageWithCGImage:cgImage];

CGImageRelease(cgImage);

The value adjustedImage effectively accumulates the effects of the Core Image filters. This all goes in its own method, which is called whenever any of your slider values change.

like image 76
warrenm Avatar answered Oct 01 '22 17:10

warrenm


The problem is that you're setting the input image for all of them to the aCIImage. You need to do something like this:

[filter1 setValue:aCIImage forKey:@"inputImage"];

filter1Output = [filter1 outputImage];
[filter2 setValue:filter1Output forKey:@"inputImage"];

etc.

like image 44
user1118321 Avatar answered Oct 01 '22 18:10

user1118321