如何使用Core Image过滤器有效地平衡图像?

时间:2015-05-21 01:09:50

标签: cocoa core-image

我尝试使用Core Image过滤器在我的Mac应用中为图像添加一些色彩校正。首先,我正在考虑允许自定义白平衡,从图像中删除强制转换。看起来CIWhitePointAdjust正是我正在寻找的,但在尝试之后,我不确定我是否错误地使用它,或者它是不是做我想的。

从这张图片开始,随着年龄变黄,右边缘有一条白色的细条:

Original image

我应用过滤器,如下所示:

NSColor *whiteSample = // Chosen from the speech bubble's background
CIColor *whiteInputColor = [[CIColor alloc] initWithColor:whiteSample];

layer.filters = @[
    [CIFilter filterWithName:@"CIWhitePointAdjust"
         withInputParameters:@{kCIInputColorKey: whiteInputColor}]
];

并获取此图片:

Image after applying CIFilter

请注意,它看起来比原始颜色更暗,更黄(与我想要的效果相反)。我一直期待一种效果更像是在Photoshop中执行自动颜色,如下所示:

Photoshopped color balance

我是否错误地使用CIWhitePointAdjust,还是这项工作的错误工具?如果其他过滤器或过滤器组合效果更好,我很乐意知道。

由于我操作已经在CALayer个对象中的图像,因此Core Image过滤器看起来确实是正确的选择,但如果这只能通过其他方式实现,我就会打开那个。

更新

信号处理网站上的helpful answer为我提供了我尝试实施的名称。从广义上讲,它被称为直方图均衡。我试图弄清楚是否有使用Core Image过滤器执行该过程的方法,到目前为止,它看起来并不太有希望(没有我自己编写)。

3 个答案:

答案 0 :(得分:3)

好的,所以我想我已经把它钉了!这是我从https://stackoverflow.com/a/30447041/734860和几个胶水中捣乱的原因:

@import Accelerator;

// I haven't yet found a way to do it within Core Image

// use this when you need to CIImage* -> CGImageRef
CIImage *ciImage = [CIImage imageWithCGImage:cgImage];

...

// use this when you need to CGImageRef -> CIImage*
CIContext* context = [[CIContext alloc] init];
CGImageRef cgImage = [context createCGImage:ciImage fromRect:ciImage.extent];

...

// the algorithm itself, which uses vImage and has to convert to/from it via CGImage
CGImageRef CreateEqualisedCGImageFromCGImage(CGImageRef original)
{
    vImage_Error err;
    vImage_Buffer _img;
    vImage_CGImageFormat format = {
        .bitsPerComponent = 8,
        .bitsPerPixel = 32,
        .colorSpace = NULL,
        .bitmapInfo = (CGBitmapInfo)kCGImageAlphaFirst,
        .version = 0,
        .decode = NULL,
        .renderingIntent = kCGRenderingIntentDefault,
    };

    CGFloat width = CGImageGetWidth(original);
    CGFloat height = CGImageGetHeight(original);

    vImage_Buffer _dstA, _dstR, _dstG, _dstB;

    err = vImageBuffer_InitWithCGImage(&_img, &format, NULL, original, kvImageNoFlags);
    if (err != kvImageNoError)
        NSLog(@"vImageBuffer_InitWithCGImage error: %ld", err);

    err = vImageBuffer_Init( &_dstA, height, width, 8 * sizeof( uint8_t ), kvImageNoFlags);
    if (err != kvImageNoError)
        NSLog(@"vImageBuffer_Init (alpha) error: %ld", err);

    err = vImageBuffer_Init( &_dstR, height, width, 8 * sizeof( uint8_t ), kvImageNoFlags);
    if (err != kvImageNoError)
        NSLog(@"vImageBuffer_Init (red) error: %ld", err);

    err = vImageBuffer_Init( &_dstG, height, width, 8 * sizeof( uint8_t ), kvImageNoFlags);
    if (err != kvImageNoError)
        NSLog(@"vImageBuffer_Init (green) error: %ld", err);

    err = vImageBuffer_Init( &_dstB, height, width, 8 * sizeof( uint8_t ), kvImageNoFlags);
    if (err != kvImageNoError)
        NSLog(@"vImageBuffer_Init (blue) error: %ld", err);

    err = vImageConvert_ARGB8888toPlanar8(&_img, &_dstA, &_dstR, &_dstG, &_dstB, kvImageNoFlags);
    if (err != kvImageNoError)
        NSLog(@"vImageConvert_ARGB8888toPlanar8 error: %ld", err);

    err = vImageEqualization_Planar8(&_dstR, &_dstR, kvImageNoFlags);
    if (err != kvImageNoError)
        NSLog(@"vImageEqualization_Planar8 (red) error: %ld", err);

    err = vImageEqualization_Planar8(&_dstG, &_dstG, kvImageNoFlags);
    if (err != kvImageNoError)
        NSLog(@"vImageEqualization_Planar8 (green) error: %ld", err);

    err = vImageEqualization_Planar8(&_dstB, &_dstB, kvImageNoFlags);
    if (err != kvImageNoError)
        NSLog(@"vImageEqualization_Planar8 (blue) error: %ld", err);

    err = vImageConvert_Planar8toARGB8888(&_dstA, &_dstR, &_dstG, &_dstB, &_img, kvImageNoFlags);
    if (err != kvImageNoError)
        NSLog(@"vImageConvert_Planar8toARGB8888 error: %ld", err);

    err = vImageContrastStretch_ARGB8888( &_img, &_img, kvImageNoError );
    if (err != kvImageNoError)
        NSLog(@"vImageContrastStretch_ARGB8888 error: %ld", err);

    free(_dstA.data);
    free(_dstR.data);
    free(_dstG.data);
    free(_dstB.data);

    CGImageRef result = vImageCreateCGImageFromBuffer(&_img, &format, NULL, NULL, kvImageNoFlags, &err);
    if (err != kvImageNoError)
        NSLog(@"vImageCreateCGImageFromBuffer error: %ld", err);

    free(_img.data);

    return result;
}

解决方案的优点全部归https://stackoverflow.com/users/4735340/james-bush所示,但我看起来很长时间没有成功的面向图像的解决方案(与该问题中讨论的视频处理相反),我认为像这样的现成回复是相关的。寻找' AutoLevels'在OS X或iOS上让我无处可去,我希望这可能对其他人有用。

答案 1 :(得分:0)

尝试使用autoAdjustmentFilters or autoAdjustmentFiltersWithOptions获取可能的过滤器列表...可能是后者,以便您可以排除需要面部检测的过滤器,如果您打算自动调整卡通扫描。

答案 2 :(得分:0)

斯威夫特 5

string reverse(string str)
{
    int k = str.length();
    for (int j = 0; j < k / 2; j++)
    {
        swap(str[j], str[k - j - 1]);
    }
    return str;
}