Closed scottmboring closed 12 years ago
Think of how the filters, inputs, and outputs work as a chain of operations that start with some input and end with one or more outputs. If you want to apply a brightness adjustment, followed by contrast and then saturation, you'll want to replace the appropriate segment in -viewWillAppear: above with
[gpuImage addTarget:brightnessFilter];
[brightnessFilter addTarget:contrastFilter];
[contrastFilter addTarget:saturationFilter];
[saturationFilter addTarget:imageView];
This will take your source image through each of the processing steps, ending with it being displayed in the view. The order is
Image -> brightness -> contrast -> saturation -> view
Your current code just causes the filters to step on each other's toes, so only the last filter is actually shown in the view.
As always; thanks for the speedy answer.
If I could make a suggestion; or perhaps vent my confusion.
Calling the method 'addTarget' seems incorrect since it would appear that it can't have more than one target. The chain architecture makes since to me and helps a lot with understanding the input/output interfaces; in particular because a filter is both an input and an output. Would the method be better named 'setTarget'? What situation(s) would an output have more than one target?
Documenting that the GPUFilters are a chaining architecture have been really helpful. I expected that there was some chaining taking place somewhere; the CIFilters do this automatically (as I understand it) choosing the appropriate order for the filters. The manual chaining is simpler and perhaps better than the automatic approach; but it was not clear to me that this is how it worked.
Thanks again, Scott B
From: Brad Larson reply@reply.github.com To: scottmboring scottmboring@yahoo.com Sent: Sunday, July 1, 2012 3:28 PM Subject: Re: [GPUImage] How to add multiple filters to a picture (#233)
Think of how the filters, inputs, and outputs work as a chain of operations that start with some input and end with one or more outputs. If you want to apply a brightness adjustment, followed by contrast and then saturation, you'll want to replace the appropriate segment in -viewWillAppear: above with
[gpuImage addTarget:brightnessFilter]; [brightnessFilter addTarget:contrastFilter]; [contrastFilter addTarget:saturationFilter];
[saturationFilter addTarget:imageView];
This will take your source image through each of the processing steps, ending with it being displayed in the view. The order is
Image -> brightness -> contrast -> saturation -> view
Your current code just causes the filters to step on each other's toes, so only the last filter is actually shown in the view.
Reply to this email directly or view it on GitHub: https://github.com/BradLarson/GPUImage/issues/233#issuecomment-6697640
The reason for -addTarget: is that an individual filter or input can have multiple targets for its output. See the MultiViewFilterExample for this in action, where the one camera input has four targets for simultaneous display. Some targets, though, can only take one input, which was what you were hitting here.
For simple linear chains of filters I could probably find a way to simplify some of the setup, but order of operation does matter for many filters, so I need people to explicitly state that. Also, some filter paths can branch, for use in things like blending (the unsharp mask operation is a good example of this), so I want to make sure we still have the flexibility to perform these operations.
The proper solution might just be better documentation on how this all works. I'll see if I can expand on what I've already written.
I want to add 3 filters to a picture. I have a tool bar and slider; based on the toolbar selection, the slider adjusts one of the filters. All the filters should be applied though.
I'm using the following code; but only the last filter added to the imageView works.
I followed the examples and it is confusing why I would add a GPUImageView as a target for a filter. I would think the filters would be added to the GPUImagePicture and the GPUImagePicture would be added to the GPUImageView; but that does not appear to be the correct structure.
(void)viewDidLoad {
[super viewDidLoad];
CGRect frame = CGRectMake(20, 20, self.view.frame.size.width-40, self.view.frame.size.height-180); imageView = [[GPUImageView alloc] initWithFrame:frame]; [self.view addSubview:imageView];
brightnessFilter = [[GPUImageBrightnessFilter alloc] init]; brightnessFilter.brightness = 0; contrastFilter = [[GPUImageContrastFilter alloc] init]; contrastFilter.contrast = 1; saturationFilter = [[GPUImageSaturationFilter alloc] init]; saturationFilter.saturation = 1;
}
(void)viewWillAppear:(BOOL)animated {
gpuImage = [[GPUImagePicture alloc] initWithImage:appModel.document.currentPage.image];
[gpuImage addTarget:brightnessFilter]; [gpuImage addTarget:contrastFilter]; [gpuImage addTarget:saturationFilter];
[brightnessFilter addTarget:imageView]; [contrastFilter addTarget:imageView]; [saturationFilter addTarget:imageView];
[gpuImage processImage]; }
(IBAction)onSlide:(id)sender forEvent:(UIEvent *)event {
switch (mode) { case 0: brightnessFilter.brightness = slider.value; break; case 1: contrastFilter.contrast = slider.value; break; case 2: saturationFilter.saturation = slider.value; break; }
[gpuImage processImage]; }
(IBAction)onModeChange:(UISegmentedControl )sender forEvent:(UIEvent )event {
mode = sender.selectedSegmentIndex;
switch (mode) { case 0: slider.minimumValue = -1; slider.maximumValue = 1; slider.value = brightnessFilter.brightness; break; case 1: slider.minimumValue = 0; slider.maximumValue = 4; slider.value = contrastFilter.contrast; break; case 2: slider.minimumValue = 0; slider.maximumValue = 2; slider.value = saturationFilter.saturation; break; } }
Thanks for any help!