【问题标题】:How to change minimum or maximum value by CIFilter in Core image?如何通过 CIFilter 在 Core 图像中更改最小值或最大值?
【发布时间】:2013-04-17 14:47:50
【问题描述】:

我在 iOS 中绘制了几张灰度图像。灰度图像的值有最小值和最大值,即在 [41,244] 范围内的 8 位值。

我想更改最小值或最大值。我想知道如何在this list 中设置过滤器来更改最小值以及如何在this list 中设置过滤器来更改最大值?

也许下面的图画会很好看:

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

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

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

【问题讨论】:

    标签: objective-c image-processing ios6 grayscale cifilter


    【解决方案1】:

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

    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    
    

    更新

    对于 Window and Level 调整窗口范围之外的输入为零值,您希望实现如下效果:

    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]
    

    在实践中这是行不通的。这些点描述了一条样条曲线,并且在方向急剧变化(例如 b-c-d)时表现不佳。 (另外点 c 和 d(2 和 3)不能共享相同的 x 值,所以无论如何你都必须稍微增加一点,使 d.x = c.x*1.01)

    如果您使用多步过滤器,您可以获得结果。第一个过滤器适当地使用CIToneCurve(这是正确的窗口/级别算法,不会尝试将最大级别降低到零)。

            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]
    

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

            filter2 = [filter copy];
    

    应用 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"];
    

    现在分色到 1 位调色板

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

    反转结果

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

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

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

    原创

    filter1 CIToneCurve

    filter2CIColorControls

    filter3 CIColorPosterize

    filter4 CIColorInvert

    filter5 CIDarkenBlendMode

    如果您查看 Brad Larson 的 GPUImage,您应该会发现 GPUImageLuminanceThresholdFilter 会更好地替换过滤器 2->5。

    【讨论】:

    • 实际上我想在灰色原始数据的每个值上应用a linear formula,当该值超出窗口时,我想将其设置为零。所以输入是窗口和水平值,输出是计算值。你做过这样的事吗?
    • 完美的例子和答案。谢谢你。
    【解决方案2】:

    对于 CIFilter 中的每个效果,我们都有最小值和最大值。我们可以在代码中修复该值,否则如果您想修复绘图,我们通过使用UISlider 为滑块完成它,给定最小值和最大值作为该过滤器的范围,然后我们可以对该滑块执行操作,因此当用户移动效果时也自动更改。

    【讨论】:

      猜你喜欢
      • 2011-04-21
      • 2014-04-17
      • 1970-01-01
      • 1970-01-01
      • 2015-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-23
      相关资源
      最近更新 更多