Core Image El filter de brillo CIColorControls crea un efecto incorrecto. ¿Cómo cambio la luminancia de mi image?

Estoy creando un selector de color para iOS. Me gustaría permitir al usuario seleccionar el brillo (luminancia) y hacer que la rueda de color refleje este cambio. Estoy usando Core Image para modificar el brillo con el filter CIColorControls. Aquí está mi código:

-(CIImage *)oldPhoto:(CIImage *)img withBrightness:(float)intensity { CIFilter *lighten = [CIFilter filterWithName:@"CIColorControls"]; [lighten setValue:img forKey:kCIInputImageKey]; [lighten setValue:@((intensity * 2.0) - 1.0) forKey:@"inputBrightness"]; return lighten.outputImage; } 

Así es como se ve la rueda de colors con intensidad = 0.5 (inputBrightness = 0):

Mi imagen con inputBrightness = 0

El problema es que la rueda de color se ve mal cuando la intensidad es <0.5. Por ejemplo, así es como se ve con intensidad = 0.3 (inputBrightness = -0.4):

Mi imagen con inputBrightness = -0.4

Observe que hay un círculo negro en el centro, y el rest de la image tampoco se ha oscurecido correctamente. Se supone que es una rueda de color HSL, así que supongo que lo que quiero cambiar es la luminancia, no el brillo.

Primero, ¿alguien puede explicar por qué la image se ve así? No soy un experto en color; parece extraño que el centro del círculo se vuelva rápidamente negro mientras que los bordes no se oscurecen mucho.

Segundo, ¿cómo puedo lograr el efecto que quiero?

Así es como realmente QUIERO que la image se vea:

Imagen con luminancia = 0.3, generada con la función HSL en la CPU (demasiado lenta)

Esto se creó con una function HSL personalizada y luminancia = 0.3. Esto se ejecuta en la CPU, por lo que es demasiado lento para mis necesidades. Estaría encantado de publicar el código para esta function HSL, pero no lo incluyo porque no parecía inmediatamente relevante. Si quieres verlo, solo pregunta.

Por favor, hágamelo saber si tiene alguna pregunta, o si algo parece no está claro. ¡Gracias!

También encontré que la no linealidad de kCIInputBrightnessKey de CIColorControls era molesta. CIToneCurve un CIToneCurve lineal:

 /** Change luminosity of `CIImage` @param inputImage The `CIImage` of the image to have it's luminosity changed. @param luminosity The percent change of the luminosity, ranging from -1.0 to 1.0. @return `CIImage` of image with luminosity changed. If luminosity of 0.0 used, original `inputImage` is returned. */ - (CIImage *)changeLuminosityOfCIImage:(CIImage *)inputImage luminosity:(CGFloat)luminosity { if (luminosity == 0) return inputImage; NSParameterAssert(luminosity >= -1.0 && luminosity <= 1.0); CIFilter *toneCurveFilter = [CIFilter filterWithName:@"CIToneCurve"]; [toneCurveFilter setDefaults]; [toneCurveFilter setValue:inputImage forKey:kCIInputImageKey]; if (luminosity > 0) { [toneCurveFilter setValue:[CIVector vectorWithX:0.0 Y:luminosity] forKey:@"inputPoint0"]; [toneCurveFilter setValue:[CIVector vectorWithX:0.25 Y:luminosity + 0.25 * (1 - luminosity)] forKey:@"inputPoint1"]; [toneCurveFilter setValue:[CIVector vectorWithX:0.50 Y:luminosity + 0.50 * (1 - luminosity)] forKey:@"inputPoint2"]; [toneCurveFilter setValue:[CIVector vectorWithX:0.75 Y:luminosity + 0.75 * (1 - luminosity)] forKey:@"inputPoint3"]; [toneCurveFilter setValue:[CIVector vectorWithX:1.0 Y:1.0] forKey:@"inputPoint4"]; } else { [toneCurveFilter setValue:[CIVector vectorWithX:0.0 Y:0.0] forKey:@"inputPoint0"]; [toneCurveFilter setValue:[CIVector vectorWithX:0.25 Y:0.25 * (1 + luminosity)] forKey:@"inputPoint1"]; [toneCurveFilter setValue:[CIVector vectorWithX:0.50 Y:0.50 * (1 + luminosity)] forKey:@"inputPoint2"]; [toneCurveFilter setValue:[CIVector vectorWithX:0.75 Y:0.75 * (1 + luminosity)] forKey:@"inputPoint3"]; [toneCurveFilter setValue:[CIVector vectorWithX:1.0 Y:1 + luminosity] forKey:@"inputPoint4"]; } return [toneCurveFilter outputImage]; } 

Aquí está su image, networkinguciendo la luminosidad en un 30% usando la rutina anterior:

reducido

Se puede hacer con CIToneCurve . Ya sea que sea más rápido que su rutina, tendrá un punto de reference.

Pruebe esto y cambie el valor con un control deslizante:

 - (void)viewDidLoad{ UIImage *aUIImage = showPickedImageView.image; CGImageRef aCGImage = aUIImage.CGImage; aCIImage = [CIImage imageWithCGImage:aCGImage]; context = [[CIContext contextWithOptions:nil] retain]; brightnessFilter = [[CIFilter filterWithName:@"CIColorControls" keysAndValues: @"inputImage", aCIImage, nil] retain]; } - (IBAction)brightnessSliderValueChanged:(id)sender { [brightnessFilter setValue:[NSNumber numberWithFloat:brightnessSlider.value ] forKey: @"inputBrightness"]; outputImage = [brightnessFilter outputImage]; CGImageRef cgiig = [context createCGImage:outputImage fromRect:[outputImage extent]]; newUIImage = [UIImage imageWithCGImage:cgiig]; CGImageRelease(cgiig); [showPickedImageView setImage:newUIImage]; } 

El filter CIColorControls funciona según lo diseñado. Simplemente agrega su parámetro de brillo a los valores rojo, verde y azul de cada píxel. Si un brillo negativo toma el píxel por debajo de 0, se graba en negro. Si un brillo positivo lo empuja sobre 1, se queda en blanco. (En realidad, cada canal se separa por separado …)

Otro problema es que CIColorControls funciona en el espacio de color RGB. HSL es muy diferente. Esta es la razón por la que su rueda de color base se ve muy diferente del selector de color estándar de Apple.

Referencia útil