What is the best filter for color balance #193

OlyRice opened this Issue Jun 12, 2012 · 30 comments

8 participants



What would be the best filter to use to mimic the photoshop color balance effect, does anyone know? I have been looking at GPUImageToneCurveFilter but i don't know if there is anything else that i could use.



you can look in gimp source code, it does that.


Here's a discussion about reusing GIMP's colour balance filter:
People there ended up producing this code: http://forum.doom9.org/attachment.php?attachmentid=12770&d=1334689130
I created a GPUImage filter out of it but unfortunately the result is not identical to Photoshop.


But does it do it like GIMP?


Turns out the color balance implementation I mentioned before is no longer used by GIMP.
Using latest GIMP 2.8.0 source code I've made a new version of the filter and the result is very close to GIMP now.
However it is still quite different from Photoshop color balance filter :(

Both versions of the shader are here:
Currently it is only implemented for Midtones

Please let me know what you think.


Personally, "very close to GIMP" is good enough, IMO. I think a photoshop-like implementation is could to be difficult, as you're trying to figure out a black box. At least anyone can download and use GIMP and fiddle with settings before committing it to code.
Are there any other filters you'd be willing to try? I spent some time with Hue adjustment, based off a stack overflow discussion, but I'm not satisfied with the results. See #276 for the details. Maybe you could do better :)


@liovch Thanks for posting. But, just looking at the source code I can tell it will be slow ;)
Wondering if there's a way to go about this without resorting to HSL conversions


@iamcam I'll try to add implementation for shadows and highlights to the colour balance code and push a filter into a GPUImage fork.
I had a brief look at the GIMP's source code for Hue/Saturation adjustment, it should be possible to make a GPUImage filter out of it. I'll see if I can do this later today.

@alariccole Preserve luminosity part is very slow because of colour space conversion. The only thing which comes to mind is to use approximation of warping colour space from hexagon into circle: http://en.wikipedia.org/wiki/HSL_and_HSV#Hue_and_chroma
But then the error in saturation will be up to 13.4%
I'll see if I can find more efficient way for RGB<->HSL conversion.


@liovch Much appreciated! I'm interested to see what the comparison will be.


I've pushed the color balance filter:

As far as I can see the results are identical to GIMP 2.8.0 (Windows version).
There is some confusion with color balance implementation in GIMP.
Color balance filter from version 2.8.0 uses actual color value as a tone, however in the latest source lightness is used instead. I have commented out the 2nd version for now, but after the new version of GIMP is released we can change GPUImage filter to correspond. Also I believe it is more correct to use lightness value.


If that filter is clean of GPL code from GIMP, send me a pull request for it and I'll pull it into the framework.


Generally (not pertaining to just this filter), is it the specific code/algorithm that is under GPL, or the math the algorithm represents? It seems that there may few ways to represent specific transformations, all of which probably existed before the GIMP authors started writing their transformation code.


Specific code (variables, order, etc.). If you can reimplement the same algorithm in a cleanroom fashion such that no code remains from the original GPL source, you should be in the clear.


@liovch I think if you could find the relevant algorithm either on wikipedia or some kind of academic source, you should be able to translate it into your own code. I don't remember how to do any vector math from school, and I have even less understanding how it applies to computer science, but you may be able to glean some information from the Wikipedia atricle.


@liovch: thank you for sharing. I'm a newbie , I have a question : How to calculate the shadowshift, midtoneshift, hightlightshift vectors from values in the color balance diaglog of photoshop or gimp ?


@dangthequan I don't think you'll be able to 100% match Photoshop color balance filter with GPUImage filter, which was designed to be similar to GIMP 2.8.0 implementation.

@iamcam I have an idea of a generic filter which can be used for any color modification and should be able to match Photoshop very closely. I want to try it first, before spending more time on this.


@liovch yes, i known. Currently, i don't know way to map cyan-red , magenta-green, yellow-blue values to the opengl shader. Assume, i have the cyan-red value at -30, the magenta-green value at 0,the yellow-blue value at 30. So, how to pass them to shader.

I tried to pass vec3(-30, 0, 30). Please correct me.

Sorry, my graphic math is not good:D


I remember reading somewhere that the shaders only work in RGBA colorspace, so you'll have to convert to another colorspace in order to use your values (would that be CMYK?).


@dangthequan GPUImage color balance filter has 3 input vectors: shadows, midtones, and highlights. Each vector has 3 components, one for each color component adjustment (cyan/red, magenta/green, yellow/blue). The range of each vector component is [-1; 1], so if you want to convert from [-100; 100] range you can divide each number by 100:
e.g. set shadows vector to vec3(-0.3, 0, 0.3)


thank you very much. I have a trouble . In the output image, some pixels have darker shadow tone than normal. How do i remove it.

Can you explain for me how to calculate the hightlight, midtone, shadow vectors ? What are "a", "b", "scale" values ?


@iamcam @dangthequan I've made a GPUImageLookupFilter which can be used to create Instagram-like filters. I have pushed it into my fork along with some sample lookup tables. You can find it here: https://github.com/liovch/GPUImage
I also wrote a blog post to explain the approach in more detail:


@iamcam I've made a simple program to generate lookup.png for the whole RGB range. Then I open this image in Photoshop and apply all the filters to it. Then the modified color grid is used as a lookup table for GPUImageLookupFilter. There are some examples in GPUImageLookupFilter.h


@liovch Interesting. I was going to refactor the tone curve filter to pull out the color mapping portion of that, but that handles color mapping on a separate red, green, and blue channel basis. It looks like your lookup filter does it on three-color pairs, which I hadn't thought to do. Again, if you'd like me to roll this in, just send a pull request and I'll do so.


@BradLarson It would be great if you could pull this into trunk, but I'm still not 100% confident my implementation is correct. So maybe it worth implementing few more filters using this approach before integrating it.
I was also going to write some filters for Effect group based on this approach, but not sure what is the best way to wrap something like this into GPUImageFilter?

  • (UIImage)applyMissEtikateFilter:(UIImage)image
    GPUImagePicture *stillImageSource = [[[GPUImagePicture alloc] initWithImage:image] autorelease];
    GPUImagePicture *lookupImageSource = [[[GPUImagePicture alloc] initWithImage:[UIImage imageNamed:@"lookup_etikate.png"]] autorelease];

    GPUImageLookupFilter *lookupFilter = [[[GPUImageLookupFilter alloc] init] autorelease];
    [stillImageSource addTarget:lookupFilter];
    [lookupImageSource addTarget:lookupFilter];

    [stillImageSource processImage];
    [lookupImageSource processImage];
    return [lookupFilter imageFromCurrentlyProcessedOutput];

One other thing is the size of the tables. Basic lookup table is only 2Kb in size, but complex filters decrease the compression ratio, and the largest lookup texture I have at the moment is 300Kb. Not sure if it's ok to add these as resources for the framework.


@liovch Quite a few of the existing filters are groups of others. Look at something like the GPUImageGaussianSelectiveBlurFilter, which chains a Gaussian blur with a custom blend. You could use something like that as a template, and build a custom GPUImageFilterGroup to contain your new filter. To the outside world, these look like individual filters.


@liovch : i found an example on github (https://github.com/victusfate/color-balance). This example has an shadow and midtone upper bound, it generates the result similar to gimp and photoshop and more correctly, how do i add these values to opengl shader of the color balance filter?


@dangthequan The particular implementation of GIMP colour balance filter I worked with doesn't have upper/lower bound parameters, and I'm not sure how exactly those bounds should be applied. It's not easy for me to figure out from the source code you've mentioned.


@dangthequan , @liovch : I tried your link (https://github.com/victusfate/color-balance). It seem wrong. The result look worse than GIMP. In my opinion, I think using threshold value to determine shadow, midtone, highlight color in that code can not give us the smooth result like Gimp. Moreover, Gimp's color balance currently has problem as Gimp community has complained.
Photoshop's Color Balance is still mystery blackbox

@BradLarson BradLarson closed this Sep 5, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment