目标C提高CIImage的过滤速度



我编写了以下代码来将Sepia过滤器应用于图像:

- (void)applySepiaFilter {
    // Set previous image
    NSData *buffer = [NSKeyedArchiver archivedDataWithRootObject: self.mainImage.image];
    [_images push:[NSKeyedUnarchiver unarchiveObjectWithData: buffer]];

    UIImage* u = self.mainImage.image;
    CIImage *image = [[CIImage alloc] initWithCGImage:u.CGImage];
    CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone"
                                  keysAndValues: kCIInputImageKey, image,
                        @"inputIntensity", @0.8, nil];
    CIImage *outputImage = [filter outputImage];
    self.mainImage.image = [self imageFromCIImage:outputImage];
}
- (UIImage *)imageFromCIImage:(CIImage *)ciImage {
    CIContext *ciContext = [CIContext contextWithOptions:nil];
    CGImageRef cgImage = [ciContext createCGImage:ciImage fromRect:[ciImage extent]];
    UIImage *image = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);
    return image;
}

当我运行这个代码时,它似乎滞后了1-2秒。我听说核心图像比核心图形快,但我对渲染时间并不满意。我想知道这是否会在CoreGraphics甚至OpenCV(项目中其他地方正在使用)中更快地处理?如果没有,有什么方法可以优化这个代码以更快地运行吗?

根据图像的大小,我几乎可以保证在核心图形中的速度会比使用核心图像慢。如果图像很小,Core Graphics可能很好,但如果你要进行大量处理,它将比使用GPU渲染慢得多。

Core Image的速度非常快,但是,你必须非常清楚发生了什么。Core Image的大部分性能打击都是由于上下文的设置,以及将图像复制到Core Image或从Core Image复制图像。除了复制字节之外,Core Image还可以在图像格式之间进行转换。

您的代码每次都在执行以下操作:

  • 创建CIContext。(慢)
  • 从CGImage中获取字节并创建CIImage
  • 正在将图像数据复制到GPU(速度较慢)
  • 处理Sepia过滤器(快速)
  • 正在将结果图像复制回CGImage。(慢)

这不是达到最高性能的秘诀。来自CGImage的字节通常会存在于CPU内存中,但Core Image希望使用GPU进行处理。

获得核心图像的最佳性能文档:中提供了关于性能考虑的优秀参考

  • 不要每次渲染时都创建CIContext对象。上下文存储了大量的状态信息;重用它们更有效
  • 评估您的应用程序是否需要颜色管理。除非你需要,否则不要使用它。请参阅你的应用程序需要颜色管理吗
  • 使用GPU上下文渲染CIImage对象时,请避免使用核心动画。如果需要同时使用两者,可以将两者设置为使用CPU。

  • 确保图像不超过CPU和GPU限制。(iOS)

  • 尽可能使用较小的图像。性能随输出像素的数量而变化。可以将"核心图像"渲染到较小的视图、纹理或帧缓冲区中。允许核心动画升级到显示大小。

  • 使用Core Graphics或Image I/O函数裁剪或缩小采样,例如函数CGImageCreateWithImageInRect或CGImageSourceCreateThumbnailAtIndex。

  • UIImageView类最适合于静态图像。如果您的应用程序需要获得最佳性能,请使用较低级别的API。

  • 避免CPU和GPU之间不必要的纹理传输。在应用内容比例因子之前,渲染到与源图像大小相同的矩形。

  • 考虑使用更简单的过滤器,可以产生类似于算法过滤器的结果。例如,CIColorCube可以产生类似于CISepiaTone的输出,并且效率更高。

  • 利用iOS 6.0及更高版本中对YUV图像的支持。

如果您需要实时处理性能,您将希望使用CoreImage可以将其输出渲染到的OpenGL视图,并将图像字节直接读取到GPU中,而不是从CGImage中提取。使用GLKView并覆盖drawRect:是一个相当简单的解决方案,可以获得Core Image可以直接渲染的视图。将数据保留在GPU上是从Core Image获得峰值性能的最佳方法。

尽量重复使用。保留一个CIContext以备后续渲染(如文档所述)。如果您最终使用OpenGL视图,这些也是您可能希望尽可能重复使用的东西。

您还可以通过使用软件渲染来获得更好的性能。软件渲染将避免复制到GPU或从GPU复制。[CIContext contextWithOptions:@{kCIContextUseSoftwareRenderer: @(YES)}]但是,这在实际渲染中会有性能限制,因为CPU渲染通常比GPU渲染慢。

所以,你可以选择你的难度来获得最大的表现。最佳性能可能更具挑战性,但一些调整可能会使您的用例达到"可接受"的性能。

最新更新