如何在iOS平台上实现快速图像filter

我正在iOS应用程序中,用户可以应用一组照片filter。 每个filter基本上都是使用特定参数设置的Photoshop动作。 这一行动是:

  • 级别调整
  • 亮度/对比度
  • 色相饱和度
  • 单个和多个叠加

我在我的代码中重复了所有这些操作,使用循环遍历图像中所有像素的算术expression式。 但是,当我在iPhone 4上运行我的应用程序时,每个filter都需要大约3-4秒的时间才能应用,这是用户等待的时间。 图像大小为640 x 640像素,是我视图尺寸的2倍,因为它显示在视网膜显示屏上。 我发现我的主要问题是每次需要调整伽玛时调用pow()C函数的级别修改。 我使用浮动不当然,因为ARMv6和ARMv7双打慢。 试图启用和禁用拇指,并得到相同的结果。

在我的应用程序中最简单的filter的例子是运行相当快(2秒)。 其他filter包括更多的expression式和pow()调用,从而使它们变慢。

https://gist.github.com/1156760

我见过一些使用Accelerate Framework vDSPmatrix转换的解决scheme,以便快速修改图像。 我也看到了OpenGL ES解决scheme。 我不确定他们能否满足我的需求。 但可能这只是把我的变化集合转换成一个好的卷积matrix的问题?

任何意见将是有益的。

谢谢,
安德烈。

对于示例代码中的filter,可以使用查找表来使其更快。 我假设你的input图像是每个颜色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个系数放在代码中。

你在这里列出的操作都不需要卷积,甚至matrix乘法。 它们都是像素操作,这意味着每个输出像素只取决于单个对应的input像素。 在多input像素影响单个输出像素的情况下,您需要考虑卷积运算,如模糊或锐化。

如果你正在寻找绝对最快的方法来做到这一点,你将要使用GPU来处理处理。 它的目的是做大规模的并行操作,比如单个像素的颜色调整。

正如我在其他答案中提到的那样,当使用OpenGL ES而不是在CPU上运行image processing操作时,我测量的性能提高了14倍 – 28倍。 你可以使用Accelerate框架来加快CPU的image processing速度(我相信苹果公司声称大约在4-5倍的提升幅度是可能的),但是它不会像OpenGL ES那么快。 然而,实现起来可能更容易,这就是为什么我有时使用OpenGL ES加速的原因。

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

我在这里提供了一个OpenGL ES 2.0着色器图像filter的例子。 做这种处理最困难的部分是build立OpenGL ES脚手架。 使用我的示例应用程序,您应该能够提取该设置代码并使用它自己的filter。 为了方便起见 ,我创build了一个名为GPUImage的开源框架,为您处理所有的OpenGL ES交互。 它几乎涵盖了上面列出的所有filter,大多数运行在2.5毫秒以下的iPhone 4上的640x480video帧,所以它们比在CPU上处理的任何东西都快。

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

除此之外,一个真正的快速检查:你打电话pow( )powf( ) ? 即使你的数据是float ,调用pow( )会得到双精度math库函数,这比单精度variablespowf( )要慢很多(你必须为floatdouble )。

第二个检查:你有没有在你的仪器中进行过滤? 你真的知道执行时间在哪里吗?还是你在猜测?

我其实是想自己做这一切,但我find了Silverberg的图像filter 。 你可以在你的图像上应用各种instagramtypes的图像filter。 这比其他图像filter好多了 – GLImageProcessing或者Cimg。

另请查看iPhone上的Instagram图片filter 。

希望这可以帮助…

从iOS 5开始,您可以使用Core Imagefilter来调整各种图像参数。

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

  - (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(build议的最大值是4.0)。
此外,在imageView的图像上计算对比度,因此重复调用此方法将累积对比度。 这意味着,如果您先调用此对比度值为2.0的方法,然后再调用对比度值3.0,则会得到对比度值增加了6.0(2.0 * 3.0)的原始图像 – 而不是5.0。

检查Apple文档以获取更多的filter和参数。

要列出代码中所有可用的filter和参数,只需运行此循环:

 NSArray* filters = [CIFilter filterNamesInCategories:nil]; for (NSString* filterName in filters) { NSLog(@"Filter: %@", filterName); NSLog(@"Parameters: %@", [[CIFilter filterWithName:filterName] attributes]); } 

这是一个古老的线索,但我从另一个链接到它,所以人们仍然阅读它。

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

核心图像使用OpenGL的着色器,所以它真的很快。 然而,使用它比OpenGL容易得多。 如果您还没有在OpenGL中工作,只想将filter应用于CGImage或UIIMage对象,则需要使用Core Imagefilter。