2

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

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

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

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

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

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

4

2 回答 2

7

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    

更新

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

在此处输入图像描述

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]

在实践中,这是行不通的。这些点描述了一条样条曲线,它在方向急剧变化(例如 bcd)时表现不佳。(此外,c 点和 d 点(2 和 3)不能共享相同的 x 值,因此在任何情况下您都必须稍微增加一点,以便 dx = cx*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"];

原来的

在此处输入图像描述

过滤器1CIToneCurve

在此处输入图像描述

过滤器2CIColorControls

在此处输入图像描述

过滤器3CIColorPosterize

在此处输入图像描述

过滤器4CIColorInvert

在此处输入图像描述

过滤器5CIDarkenBlendMode

在此处输入图像描述

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

于 2013-04-25T03:57:47.840 回答
0

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

于 2013-04-25T04:42:52.117 回答