如何在Core图像中通过CIFilter更改最小值或最大值?

mf *_* mf 1 image-processing objective-c grayscale ios6 cifilter

我正在iOS中绘制几个灰度图像.灰度图像的值具有最小值和最大值,即对于范围内的8位值[41,244].

我想改变最小值或最大值.我想知道如何在此列表中设置过滤器以更改最小值以及如何在此列表中设置过滤器以更改最大值?

也许以下绘图会很好看:

[1.读取原始灰度数据] - > [2.创建CGImageRef] - > [3.在GPU中加载参考]

到目前为止,在iOS 6中可以实时应用GPU中的过滤器.操作1或2对我来说非常慢,因为在一秒钟内我应该绘制100张图像.所以我需要在GPU中使用CIFilter.我知道如何过滤图像.但是什么过滤器可以完成我的工作?

一些示例代码对我有好处.

fou*_*dry 6

CIToneCurve应该对这种事情有好处.

- (UIImage*) applyToneCurveToImage:(UIImage*)image
{
    CIContext* context = self.context;
    CIImage* ciImage = [[CIImage alloc] initWithImage:image];

    CIFilter*   filter =
        [CIFilter filterWithName:@"CIToneCurve"
                   keysAndValues:
                kCIInputImageKey, ciImage,
                  @"inputPoint0",[CIVector vectorWithX:0.00 Y:0.3]
                 ,@"inputPoint1",[CIVector vectorWithX:0.25 Y:0.4]
                 ,@"inputPoint2",[CIVector vectorWithX:0.50 Y:0.5]
                 ,@"inputPoint3",[CIVector vectorWithX:0.75 Y:0.6]
                 ,@"inputPoint4",[CIVector vectorWithX:1.00 Y:0.7]
                 ,nil];

    CIImage* result = [filter valueForKey:kCIOutputImageKey];

    CGImageRef cgImage = [context createCGImage:result
                                            fromRect:[result extent]];
    UIImage* filteredImage = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);
    return filteredImage;
}
Run Code Online (Sandbox Code Playgroud)

self.context可以是CPU或GPU(EAGL)上下文.这些点描述了色调曲线.X是输入值,Y是输出值.在这个例子中,我们减少了斜率,因此降低了对比度.你也可以保持斜率相同,但切断极端,以减少你的最大值和最小值.

以下是在iPad mini上处理100张图像的一些测量值(每个设置平均四个读数).你会发现GPU不是神奇的子弹,只有大约60-65%的时间被吸收在周围的运动图像数据中.这些示例以UIImage开头和结尾.我用CGImage得到了非常相似的结果.

                              57x57px png  640x800px jpeg
 UIImage->CIImage->UIImage (no filtering)      
                       CPU    0.57s        2.83s   
                       GPU    0.36s        2.83s    
 UIImage->CIImage->CIFilter->UIImage
                       CPU    0.75s        4.38s    
                       GPU    0.58s        4.32s    
Run Code Online (Sandbox Code Playgroud)

更新

对于窗口和级别调整,对于窗口范围之外的输入,零值,您希望实现如下所示:

在此输入图像描述

CGFloat w;  //window
CGFloat l;  //level

              @"inputPoint0",[CIVector vectorWithX:0.0   Y:0.0]
             ,@"inputPoint1",[CIVector vectorWithX:l-w/2 Y:0.0]
             ,@"inputPoint2",[CIVector vectorWithX:l+w/2 Y:1.0]
             ,@"inputPoint3",[CIVector vectorWithX:l+w/2 Y:0.0]
             ,@"inputPoint4",[CIVector vectorWithX:1.0   Y:0.0]
Run Code Online (Sandbox Code Playgroud)

在实践中,这将不起作用.这些点描述了样条曲线,并且在方向的急剧变化(例如bcd)下表现不佳.(点c和d(2和3)也不能共享相同的x值,因此在任何情况下你都需要略微增加,以便dx = cx*1.01)

如果使用多步过滤器,则可以获得结果.第一个过滤器使用CIToneCurveapprpriately(这是正确的窗口/级别算法,而不试图将最大级别降低到零).

在此输入图像描述

        CIFilter*   filter =
        [CIFilter filterWithName:@"CIToneCurve"
                   keysAndValues:
                kCIInputImageKey, ciImage,
              @"inputPoint0",[CIVector vectorWithX:0.0   Y:0.0]
             ,@"inputPoint1",[CIVector vectorWithX:l-w/2 Y:0.0]
             ,@"inputPoint2",[CIVector vectorWithX:l     Y:0.5]
             ,@"inputPoint3",[CIVector vectorWithX:l+w/2 Y:1.0]
             ,@"inputPoint4",[CIVector vectorWithX:1.0   Y:1.0]
Run Code Online (Sandbox Code Playgroud)

我们制作过滤器的副本,因为我们将在最后一步中再次使用它:

        filter2 = [filter copy];
Run Code Online (Sandbox Code Playgroud)

应用CIColorControls滤镜可最大化对比度和亮度

        filter = [CIFilter filterWithName:@"CIColorControls"
                            keysAndValues:kCIInputImageKey,
                    [filter valueForKey:kCIOutputImageKey], nil];

        [filter setValue:[NSNumber numberWithFloat:-1]
                  forKey:@"inputBrightness"];
        [filter setValue:[NSNumber numberWithFloat:4]
                  forKey:@"inputContrast"];
Run Code Online (Sandbox Code Playgroud)

现在将其分为1位调色板

        filter = [CIFilter filterWithName:@"CIColorPosterize"
                             keysAndValues:kCIInputImageKey,
                     [filter valueForKey:kCIOutputImageKey], nil];

        [filter setValue:@2 forKey:@"inputLevels"];
Run Code Online (Sandbox Code Playgroud)

反转结果

        filter = [CIFilter filterWithName:@"CIColorInvert"
                            keysAndValues:kCIInputImageKey,
                    [filter valueForKey:kCIOutputImageKey], nil];
Run Code Online (Sandbox Code Playgroud)

现在我们将此结果用作具有窗口/水平图像的遮罩,以便将所有最大白色级别降低为黑色.

        filter = [CIFilter filterWithName:@"CIDarkenBlendMode"
                            keysAndValues:kCIInputImageKey,
                    [ filter valueForKey:kCIOutputImageKey], nil];

        [filter setValue:[filter2 valueForKey:kCIOutputImageKey]
                  forKey:@"inputBackgroundImage"];
Run Code Online (Sandbox Code Playgroud)

原版的

在此输入图像描述

过滤器1 CIToneCurve

在此输入图像描述

过滤器2 CIColorControls

在此输入图像描述

过滤器3 CIColorPosterize

在此输入图像描述

过滤器4 CIColorInvert

在此输入图像描述

filter5 CIDarkenBlendMode

在此输入图像描述

如果你看一下Brad Larson的GPUImage话,你GPUImageLuminanceThresholdFilter会发现它会更好地取代过滤器2-> 5.