Stumped próbuje dostosować odcień określonego kanału (lub może, konkretniej, określony zakres kolorów - w tym przypadku, czerwone). Patrząc na filtrze Hue, pomyślałem, że może mógłbym dostać gdzieś przez zakomentowanie zielone i niebieskie modyfikatory, wpływ zmian tylko na czerwonym kanale:GPUImage dodać regulacje barwy/koloru dla każdego kanału RGB (dopasować czerwone, aby były bardziej różowe lub pomarańczowe)
precision highp float;
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
uniform mediump float hueAdjust;
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);
void main()
{
// Sample the input pixel
highp vec4 color = texture2D(inputImageTexture, textureCoordinate);
// Convert to YIQ
highp float YPrime = dot (color, kRGBToYPrime);
highp float I = dot (color, kRGBToI);
highp float Q = dot (color, kRGBToQ);
// Calculate the hue and chroma
highp float hue = atan (Q, I);
highp float chroma = sqrt (I * I + Q * Q);
// Make the user's adjustments
hue += (-hueAdjust); //why negative rotation?
// Convert back to YIQ
Q = chroma * sin (hue);
I = chroma * cos (hue);
// Convert back to RGB
highp vec4 yIQ = vec4 (YPrime, I, Q, 0.0);
color.r = dot (yIQ, kYIQToR);
// --> color.g = dot (yIQ, kYIQToG);
// --> color.b = dot (yIQ, kYIQToB);
// Save the result
gl_FragColor = color;
}
);
Ale to właśnie opuszcza zdjęcie albo szary/niebieski i przemywa -out lub fioletowo-zielony. Czy jestem na dobrej drodze? Jeśli nie, jak mogę zmodyfikować ten filtr, aby wpływał na poszczególne kanały, pozostawiając pozostałe w nienaruszonym stanie?
Kilka przykładów:
oryginału, a efekt usiłuję osiągnąć:
(Drugi obraz jest prawie niezauważalnie jednak inna barwa kanał czerwony została wykonana nieco bardziej różowawe Muszę być w stanie dostosować go między różowy < -> pomarańczowy).
Ale oto co mam z B i G wykomentowane:
(lewy bok: < 0º, po prawej stronie:> 0 °)
Wygląda mi na to, że nie jest wpływając na odcień czerwieni w sposób, w jaki chciałbym; być może podchodzę do tego niepoprawnie, lub jeśli jestem na dobrej drodze, ten kod nie reguluje poprawnie odcienia czerwonego kanału?
(Próbowałem również osiągnąć ten efekt za pomocą GPUImageColorMatrixFilter
, ale nie bardzo się z tym pogodziłam).
Edit: oto moja obecna iteracja cieniującego używając @ kodu + GPUImage owijki VB_overflow, która jest funkcjonalnie wpływających na jakość wyświetlanego obrazu w sposób podobny do tego, co ja zmierzające do:
#import "GPUImageSkinToneFilter.h"
@implementation GPUImageSkinToneFilter
NSString *const kGPUImageSkinToneFragmentShaderString = SHADER_STRING
(
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
// [-1;1] <=> [pink;orange]
uniform highp float skinToneAdjust; // will make reds more pink
// Other parameters
uniform mediump float skinHue;
uniform mediump float skinHueThreshold;
uniform mediump float maxHueShift;
uniform mediump float maxSaturationShift;
// RGB <-> HSV conversion, thanks to http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
highp vec3 rgb2hsv(highp vec3 c)
{
highp vec4 K = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);
highp vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
highp vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
highp float d = q.x - min(q.w, q.y);
highp float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y)/(6.0 * d + e)), d/(q.x + e), q.x);
}
// HSV <-> RGB conversion, thanks to http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
highp vec3 hsv2rgb(highp vec3 c)
{
highp vec4 K = vec4(1.0, 2.0/3.0, 1.0/3.0, 3.0);
highp vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
// Main
void main()
{
// Sample the input pixel
highp vec4 colorRGB = texture2D(inputImageTexture, textureCoordinate);
// Convert color to HSV, extract hue
highp vec3 colorHSV = rgb2hsv(colorRGB.rgb);
highp float hue = colorHSV.x;
// check how far from skin hue
highp float dist = hue - skinHue;
if (dist > 0.5)
dist -= 1.0;
if (dist < -0.5)
dist += 1.0;
dist = abs(dist)/0.5; // normalized to [0,1]
// Apply Gaussian like filter
highp float weight = exp(-dist*dist*skinHueThreshold);
weight = clamp(weight, 0.0, 1.0);
// We want more orange, so increase saturation
if (skinToneAdjust > 0.0)
colorHSV.y += skinToneAdjust * weight * maxSaturationShift;
// we want more pinks, so decrease hue
else
colorHSV.x += skinToneAdjust * weight * maxHueShift;
// final color
highp vec3 finalColorRGB = hsv2rgb(colorHSV.rgb);
// display
gl_FragColor = vec4(finalColorRGB, 1.0);
}
);
#pragma mark -
#pragma mark Initialization and teardown
@synthesize skinToneAdjust;
@synthesize skinHue;
@synthesize skinHueThreshold;
@synthesize maxHueShift;
@synthesize maxSaturationShift;
- (id)init
{
if(! (self = [super initWithFragmentShaderFromString:kGPUImageSkinToneFragmentShaderString]))
{
return nil;
}
skinToneAdjustUniform = [filterProgram uniformIndex:@"skinToneAdjust"];
skinHueUniform = [filterProgram uniformIndex:@"skinHue"];
skinHueThresholdUniform = [filterProgram uniformIndex:@"skinHueThreshold"];
maxHueShiftUniform = [filterProgram uniformIndex:@"maxHueShift"];
maxSaturationShiftUniform = [filterProgram uniformIndex:@"maxSaturationShift"];
self.skinHue = 0.05;
self.skinHueThreshold = 50.0;
self.maxHueShift = 0.14;
self.maxSaturationShift = 0.25;
return self;
}
#pragma mark -
#pragma mark Accessors
- (void)setSkinToneAdjust:(CGFloat)newValue
{
skinToneAdjust = newValue;
[self setFloat:newValue forUniform:skinToneAdjustUniform program:filterProgram];
}
- (void)setSkinHue:(CGFloat)newValue
{
skinHue = newValue;
[self setFloat:newValue forUniform:skinHueUniform program:filterProgram];
}
- (void)setSkinHueThreshold:(CGFloat)newValue
{
skinHueThreshold = newValue;
[self setFloat:newValue forUniform:skinHueThresholdUniform program:filterProgram];
}
- (void)setMaxHueShift:(CGFloat)newValue
{
maxHueShift = newValue;
[self setFloat:newValue forUniform:maxHueShiftUniform program:filterProgram];
}
- (void)setMaxSaturationShift:(CGFloat)newValue
{
maxSaturationShift = newValue;
[self setFloat:newValue forUniform:maxSaturationShiftUniform program:filterProgram];
}
@end
Czy jesteś absolutnie 100% zestaw na przeprowadzenie tej pracy z GPUImage czy jesteś otwarty na innych bibliotek, które mogą być niskie niski poziom? – Loxx
Nie widzisz, że robi się znacznie niższy poziom niż OpenGL-ES? Wciąż nie ma nic takiego jak GPUImage. – brandonscript
Tak, mam na myśli przejście do czegoś podobnego do ImageMagick, jest to o wiele bardziej wymagające niż GPUImage pod względem filtrów, kolorowania itp., Przynajmniej z mojego doświadczenia. – Loxx