Closed iamcam closed 12 years ago
It would really help if someone would find a working calculation that does this. That last few I tried were rejected by people because they didn't match Core Image's hue adjustments, so I gave up. Frankly, I don't do much work on the color correcting side so I'm going to need some help here.
I saw this one the other day but couldn't figure out how to get it to compile. I have no doubt that somebody who understands GLSL could get it in no time. http://stackoverflow.com/a/9234854/694080
Edit Never mind, I fiddled enough with it and didn't realize I mis-read the post. I was able to get the shader working after some time, but the results don't seem to be correct. I'll see if i can dig anything up.
I think i'm going to pass on figuring this out. The above SO answer gets you close, but not quite all the way simply by expanding the precision of the float constants at the top (ref'd from wikipedia). Note it says approximate, which this is.
@BradLarson How approximate is acceptable enough to make it into a filter?
const highp vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);
const highp vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);
const highp vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);
const highp vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);
const highp vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);
const highp vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);
I also converted the functions over here but my output looked exactly like the the source, no matter how much i adjusted the hue. See the code below - not sure what's going on there. I believe everything is in the [0-1] range, so I should be seeing something.
NSString *const kGPUImageHueFragmentShaderString = SHADER_STRING
(
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
uniform lowp float hueAdjust;
void main ()
{
// Sample the input pixel
mediump vec4 color = texture2D(inputImageTexture, textureCoordinate);
//Make HSL from RGB
highp float r = color.r;
highp float g = color.g;
highp float b = color.b;
highp float a = color.a;
highp float maxValA = max(r, g);
highp float maxVal = max(maxValA,b);
highp float minValA = min(r, g);
highp float minVal = min(minValA, b);
highp float h = (maxVal + minVal) / 2.0;
highp float s = (maxVal + minVal) / 2.0;
highp float l = (maxVal + minVal) / 2.0;
if(maxVal == minVal){
h = s = 0.0; // achromatic
}else{
highp float d = maxVal - minVal;
s = l > 0.5 ? d / (2.0 - maxVal - minVal) : d / (maxVal + minVal);
if(maxVal == r){
h = (g - b) / d + (g < b ? 6.0 : 0.0);
} else if(maxVal == g){
h = (b - r) / d + 2.0;
} else if( maxVal == b){
h = (r - g) / d + 4.0;
}
h /= 6.0;
}
// Make the user's adjustments
h += hueAdjust;
if(s == 0.0){
r = g = b = l; // achromatic
}else{
highp float q;
if(l < 0.5){
q = l * (1.0 + s);
} else {
q = l + s - l * s;
}
highp float p = 2.0 * l - q;
highp float t = 0.0;
// //function hue2rgb(p, q, t){
// // RED
t = h + float(1/3);
if(t < 0.0) t += 1.0;
if(t > 1.0) t -= 1.0;
if(t < float(1/6)) r = p + (q - p) * 6.0 * t;
if(t < float(1/2)) r = q;
if(t < float(2/3)) r = p + (q - p) * (float(2/3) - t) * 6.0;
// GREEN
t = h;
if(t < 0.0) t += 1.0;
if(t > 1.0) t -= 1.0;
if(t < float(1/6)) g = p + (q - p) * 6.0 * t;
if(t < float(1/2)) g = q;
if(t < float(2/3)) g = p + (q - p) * (float(2/3) - t) * 6.0;
//BLUE
t = h - float(1/3);
if(t < 0.0) t += 1.0;
if(t > 1.0) t -= 1.0;
if(t < float(1/6)) b= p + (q - p) * 6.0 * t;
if(t < float(1/2)) b= q;
if(t < float(2/3)) b= p + (q - p) * (float(2/3) - t) * 6.0;
}
color.r = r;
color.g = g;
color.b = b;
highp vec4 newColor = vec4(r,g,b,a);
color.a = a;
// Save the result
gl_FragColor = newColor; // NOTHING!?!?!? UGH
}
);
Even if you have something approximate, send me a pull request for it and I'll roll it in. It's better to have something that's close than nothing at all.
I'm on the fence. A few of the samples looked fairly close, but when I started comparing other images it looks farther off. I'll fiddle with it a little bit more, then I'll post it. Worse come to worse it'll just take a little bit of fudging to get the desired effect. Maybe somebody else has an idea.
Using the updated code in the original SO question gave more accurate shifts, BUT it also tinted the entire frame, including whites... unacceptable. I couldn't quite figure out why it was shifting everything. Maybe somebody could figure it out, because I think it has potential to be a better calculation.
I'm done trying different algos, so I've posted a pull request for the accepted SO answer. Pull Req #289
@iamcam Would it be possible to add also a HueBlendfilter now where you have been able to add the HueFilter to the framework. Would be a great help ;-)
@iamcam Here's a filter based on GIMP source code: https://gist.github.com/3176346 As far as I can see it works exactly like GIMP's Hue-Saturation filter (GIMP 2.8.0 Windows).
I'm not sure if GIMP license is compatible with GPUImage, probably not. So I won't push this code into GPUImage until I or someone else rewrites it.
No, any GPL code is not compatible with this framework. I've explicitly avoided pulling anything from GIMP for that reason. A cleanroom reimplementation would be needed.
Ugh. I didn't realize gimp was GPL.
There is some expressed need, including 274, for a hue filter, as in Photoshop and other image editing apps.