核心图像CIColorControls亮度滤镜产生了错误的效果。我该如何改变我的图像亮度?

16

我正在为iOS创建一个颜色选择器。我希望用户能够选择亮度(光度),并使颜色轮反映出这种变化。我正在使用Core Image来使用CIColorControls过滤器修改亮度。以下是我的代码:

-(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;
}

下面是强度为0.5(inputBrightness = 0)时的色轮图:

My image with inputBrightness = 0

问题是当强度小于0.5时,颜色轮的颜色看起来不正确。例如,这是强度为0.3(inputBrightness = -0.4)时的图像:

My image with inputBrightness = -0.4

请注意,中间有一个黑色圆圈,并且图像的其余部分也没有被正确地变暗。这应该是一个HSL色轮,所以我猜我实际上想改变的是亮度,而不是亮度值。

首先,有人能解释一下为什么图像会出现这种情况吗?我不是颜色方面的专家;圆圈的中心很快变成了黑色,而它的边缘却没有变暗,这似乎有些奇怪。

其次,我如何实现所需的效果?

这就是我真正想要的图像:

Image with luminance = 0.3, generated with HSL function on CPU (too slow)

这是使用自定义HSL函数和亮度=0.3创建的。这在CPU上运行得太慢了,所以我很高兴将这个HSL函数的代码发布出来,但我没有包含它,因为它似乎并不立即相关。如果您想看到它,请告诉我。

如果您有任何问题或任何内容不清楚,请告诉我。谢谢!


解决问题的一种简单而可能快速的方法是在彩色圆圈上绘制一个黑色圆圈。您选择的此黑色圆圈的alpha值确定了彩色圆圈的亮度。无需重新计算所有颜色。 - mmgp
尝试在设置CIContext时将工作色彩空间更改为RGB线性。 - ccgus
3个回答

10

我也发现 CIColorControls 中的 kCIInputBrightnessKey 非线性很让人厌烦。所以我使用了一个线性的 CIToneCurve

/** 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];
}

这是您的图像,使用上述程序将亮度降低30%:

reduced

可以使用CIToneCurve完成此操作。无论它是否比您的程序更快,您都需要进行基准测试。


2
您的CIColorControls滤镜按设计要求正常工作。它只是将亮度参数添加到每个像素的红色、绿色和蓝色值中。如果负亮度使像素低于0,则剪切为黑色。如果正亮度将其推到超过1,则剪切为白色。(实际上,每个通道都会单独剪切...)
另一个问题是,CIColorControls在RGB颜色空间中工作。HSL非常不同。这就是为什么您的基本颜色轮与标准的Apple颜色选择器看起来非常不同的原因。 有用的参考资料

我觉得它按预期工作毫无意义,因为我找不到任何CIColorControls设置不改变原始图像的选项。事实上,默认值会显著改变图像,即使调整它们,我也找不到任何保持图像不受影响的值。 - Chewie The Chorkie
1
对于CIColorControls,亮度参数为0.0将不会改变图像。也就是说,它既不会增加也不会减少亮度。同样,饱和度参数为1.0或对比度参数为1.0将不会改变图像。请参阅https://developer.apple.com/library/archive/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html#//apple_ref/doc/filter/ci/CIColorControls。 - Jerry B

2
尝试使用滑块来更改值:-
- (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];
}

这并没有回答问题。这使用了相同的过滤器CIColorControls,就像他在问题中包含的第二个示例中使用的那样。这个答案只是重现了问题,而没有解决它。 - Rob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接