10

我正在开发 iOS 应用程序,用户可以在其中应用一组特定的照片过滤器。每个滤镜基本上都是一组带有特定参数的 Photoshop 动作。这些行动是:

  • 水平调整
  • 亮度/对比度
  • 色相饱和度
  • 单一和多重叠加

我已经在我的代码中重复了所有这些操作,使用算术表达式循环遍历图像中的所有像素。但是当我在 iPhone 4 上运行我的应用程序时,每个过滤器需要大约 3-4 秒才能应用,这对于用户来说是相当长的等待时间。图像大小为 640 x 640 像素,这是我的视图大小的 2 倍,因为它显示在 Retina 显示屏上。我发现我的主要问题是每次需要调整伽玛时都会调用 pow() C 函数的级别修改。当然,我使用的是浮点数而不是双精度数,因为 ARMv6 和 ARMv7 使用双精度数很慢。尝试启用和禁用 Thumb 并得到相同的结果。

我的应用程序中最简单的过滤器示例,它运行得非常快(2 秒)。其他过滤器包括更多的表达式和 pow() 调用,从而使它们变慢。

https://gist.github.com/1156760

我见过一些使用 Accelerate Framework vDSP 矩阵转换来快速修改图像的解决方案。我还看到了 OpenGL ES 解决方案。我不确定他们是否能够满足我的需求。但可能只是将我的一组更改转换为一些好的卷积矩阵?

任何意见将是有益的。

谢谢,
安德烈。

4

6 回答 6

13

对于示例代码中的过滤器,您可以使用查找表使其更快。我假设您的输入图像是每种颜色 8 位,并且您在将其传递给此函数之前将其转换为浮点数。对于每种颜色,这只给出 256 个可能的值,因此只有 256 个可能的输出值。您可以预先计算这些并将它们存储在一个数组中。这将避免pow()计算和边界检查,因为您可以将它们纳入预计算。

它看起来像这样:

unsigned char table[256];
for(int i=0; i<256; i++) {
    float tmp = pow((float)i/255.0f, 1.3f) * 255.0; 
    table[i] = tmp > 255 ? 255 : (unsigned char)tmp;
}

for(int i=0; i<length; ++i)
    m_OriginalPixelBuf[i] = table[m_OriginalPixelBuf[i]];

在这种情况下,您只需执行pow()256 次而不是 3*640*640 次。您还可以避免由于在主图像循环中检查边界而导致的分支,这可能会很昂贵。您也不必转换为浮动。

甚至更快的方法可能是在程序之外预先计算表格,然后将 256 个系数放入代码中。

您在那里列出的所有操作都不需要卷积甚至矩阵乘法。它们都是逐像素操作,这意味着每个输出像素只依赖于单个对应的输入像素。对于多个输入像素影响单个输出像素的模糊或锐化等操作,您需要考虑卷积。

于 2011-08-19T14:20:20.207 回答
10

如果您正在寻找绝对最快的方法来执行此操作,您将需要使用 GPU 来处理处理。它旨在进行大规模并行操作,例如对单个像素进行颜色调整。

正如我在其他答案中提到的那样,当使用 OpenGL ES 而不是在 CPU 上运行图像处理操作时,我测量到性能提高了 14 倍至 28 倍。您可以使用 Accelerate 框架在 CPU 上进行更快的图像处理(我相信 Apple 声称在这里可以实现约 4-5 倍的提升),但它不会像 OpenGL ES 那样快。然而,它更容易实现,这就是为什么我有时会在 OpenGL ES 上使用 Accelerate。

iOS 5.0 还带来了来自桌面的 Core Image,它为您提供了围绕这些 GPU 上图像调整的一个很好的包装。但是,在直接使用 OpenGL ES 2.0 着色器时,iOS Core Image 实现存在一些限制。

我在这里的文章中介绍了一个 OpenGL ES 2.0 着色器图像过滤器的示例。进行这种处理最困难的部分是设置 OpenGL ES 脚手架。 在那里使用我的示例应用程序,您应该能够提取该设置代码并使用它应用您自己的过滤器。为了使这更容易,我创建了一个名为GPUImage的开源框架,它为您处理所有 OpenGL ES 交互。它几乎具有您上面列出的所有过滤器,并且大多数在 iPhone 4 上运行 640x480 帧视频的时间不到 2.5 毫秒,因此它们比 CPU 上处理的任何东西都快得多。

于 2011-08-19T18:11:51.983 回答
3

正如我在评论中所说,您也应该在官方 Apple 开发者论坛上发布这个问题。

除此之外,一个真正的快速检查:你打电话pow( )还是powf( )?即使您的数据是float,调用pow( )也会为您提供双精度数学库函数,该函数比单精度变体慢得多powf( )(并且您还必须为float和之间的额外转换付费double)。

第二次检查:您是否在 Instruments 中配置了您的过滤器?你真的知道执行时间花在了哪里,还是你在猜测?

于 2011-08-19T16:49:41.660 回答
3

我实际上想自己做这一切,但我找到了 Silverberg 的Image Filters。您可以在图像上应用各种 instagram 类型的图像过滤器。这比其他图像过滤器——GLImageProcessing 或 Cimg 好得多。

还要检查iPhone 上的 Instagram 图像过滤器

希望这可以帮助...

于 2011-08-19T16:57:00.827 回答
2

从 iOS 5 开始,您可以使用 Core Image 过滤器来调整一系列图像参数。

例如,要调整对比度,这段代码就像一个魅力:

    - (void)setImageContrast:(float)contrast forImageView:(UIImageView *)imageView {

    if (contrast > MIN_CONTRAST && contrast < MAX_CONTRAST) {
        CIImage *inputImage = [[CIImage alloc] initWithImage:imageView.image];
        CIFilter *exposureAdjustmentFilter = [CIFilter filterWithName:@"CIColorControls"];
        [exposureAdjustmentFilter setDefaults];
        [exposureAdjustmentFilter setValue:inputImage forKey:@"inputImage"];
        [exposureAdjustmentFilter setValue:[NSNumber numberWithFloat:contrast] forKey:@"inputContrast"]; //default = 1.00
//        [exposureAdjustmentFilter setValue:[NSNumber numberWithFloat:1.0f] forKey:@"inputSaturation"]; //default = 1.00
//        [exposureAdjustmentFilter setValue:[NSNumber numberWithFloat:0.0f] forKey:@"inputBrightness"];
        CIImage *outputImage = [exposureAdjustmentFilter valueForKey:@"outputImage"];
        CIContext *context = [CIContext contextWithOptions:nil];
        imageView.image = [UIImage imageWithCGImage:[context createCGImage:outputImage fromRect:outputImage.extent]];
    }

}

NB 对比度的默认值为 1.0(建议的最大值为 4.0)。
另外,这里对imageView的图像计算对比度,所以重复调用这个方法会累积对比度。意思是,如果你先用对比度值 2.0 调用这个方法,然后再用对比度值 3.0 调用这个方法,你将得到对比度值增加 6.0 (2.0 * 3.0) 的原始图像 - 而不是 5.0。

查看Apple 文档以获取更多过滤器和参数。

要在代码中列出所有可用的过滤器和参数,只需运行以下循环:

NSArray* filters = [CIFilter filterNamesInCategories:nil];
for (NSString* filterName in filters)
{
    NSLog(@"Filter: %@", filterName);
    NSLog(@"Parameters: %@", [[CIFilter filterWithName:filterName] attributes]);
}
于 2013-07-17T05:05:53.740 回答
0

这是一个旧线程,但我从 SO 上的另一个链接得到它,所以人们仍然阅读它。

在 iOS 5 中,Apple 增加了对 Core Image 的支持,以及相当数量的 Core 图像过滤器。我很确定OP提到的所有内容都可用

Core Image 在后台使用 OpenGL 着色器,因此速度非常快。然而,它比 OpenGL 更容易使用。如果您还没有在 OpenGL 中工作,并且只想将过滤器应用于 CGImage 或 UIIMage 对象,那么 Core Image 过滤器是您的最佳选择。

于 2012-05-27T23:40:54.677 回答