【问题标题】:Objective C improve CIImage filter speedObjective C 提高 CIImage 过滤速度
【发布时间】:2016-04-28 20:40:34
【问题描述】:

我编写了以下代码来将棕褐色滤镜应用于图像:

- (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(项目的其他地方正在使用)中进行更快的处理?如果没有,有什么办法可以优化此代码以更快地运行?

【问题讨论】:

  • 你有没有使用 Instruments 来找出这里真正慢的地方?
  • @zneak 那是什么乐器?
  • 别想了,像“时间探查器”之类的东西。

标签: objective-c performance opencv core-graphics core-image


【解决方案1】:

我几乎可以保证它在 Core Graphics 中会比使用 Core Image 慢,具体取决于图像的大小。如果图像很小,Core Graphics 可能没问题,但如果你进行大量处理,它会比使用 GPU 渲染慢得多。

Core Image 非常快,但是,您必须非常清楚正在发生的事情。 Core Image 的大部分性能损失是由于设置了上下文,以及将图像复制到 Core Image 或从 Core Image 复制图像。除了复制字节之外,Core Image 还可能在图像格式之间进行转换。

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

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

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

Getting the Best Performance Core Image 文档中提供了有关性能考虑的出色参考:

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

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

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

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

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

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

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

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

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

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

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

因此,您可以选择难度级别以获得最佳性能。最佳性能可能更具挑战性,但一些调整可能会让您的用例获得“可接受”的性能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多