首页 > 解决方案 > 在 Swift 中加快 UIImage 处理速度

问题描述

我正在尝试应用下一个代码为从图库中获取的图像着色:

func zoeFilter() -> UIImage? {
        let brownColor = UIColor (red: 128/255, green: 0, blue: 0, alpha: 1)
        let colorRect = CGRect (origin: .zero, size: self.size)

        let renderer = UIGraphicsImageRenderer (bounds: colorRect)

        let brownColoredImage = renderer.image { ctx in
            ctx.cgContext.setFillColor(greyColor.cgColor)
            ctx.fill(colorRect)
        }

        let outBrown0Image = renderer.image { ctx in
            ctx.cgContext.setFillColor(UIColor.white.cgColor)
            ctx.fill(colorRect)
            self.draw(in: colorRect, blendMode: .normal, alpha: 1)
            brownColoredImage.draw(in: colorRect, blendMode: .colorDodge, alpha: 1)
        }

        let outBrownImage = renderer.image { ctx in
            self.draw(in: colorRect, blendMode: .normal, alpha: 1)
            outBrown0Image.draw(in: colorRect, blendMode: .multiply, alpha: 1)
        }

        return outBrownImage
    }

但是处理图像大约需要 14 秒,这对用户体验来说并不是很好......

你知道我怎样才能得到相同的结果但加速图像处理?

你有什么秘诀吗?

提前致谢!

最终解决方案

func zoeFilter() -> UIImage? {
        let inImage = CIImage (image: self)

        let SRGBImage = inImage?.applyingFilter("CILinearToSRGBToneCurve")

        let brownColor = CIColor (red: 128/255, green: 0, blue: 0, alpha: 1)
        let colorRect = CGRect (origin: .zero, size: self.size)

        dynamic let colorFilter = CIFilter(name: "CIConstantColorGenerator")
        dynamic let colorizeFilter = CIFilter (name: "CIColorDodgeBlendMode")
        dynamic let multiplyFilter = CIFilter (name: "CIMultiplyBlendMode")

        colorFilter?.setValue(brownColor, forKey: kCIInputColorKey)
        let brownSolidImage = colorFilter?.outputImage?.cropped(to: colorRect)

        colorizeFilter?.setValue(SRGBImage, forKey: kCIInputBackgroundImageKey)
        colorizeFilter?.setValue(brownSolidImage, forKey: kCIInputImageKey)
        let outBrown0Image = colorizeFilter?.outputImage

        multiplyFilter?.setValue(SRGBImage, forKey: kCIInputBackgroundImageKey)
        multiplyFilter?.setValue(outBrown0Image, forKey: kCIInputImageKey)
        let outBrownImage = multiplyFilter?.outputImage

        let linearImage = outBrownImage?.applyingFilter("CISRGBToneCurveToLinear")

        let cgImage = CIContext().createCGImage(linearImage!, from: linearImage!.extent)
        return UIImage (cgImage: cgImage!)
    }

标签: swiftxcodeimage-processinguiimage

解决方案


最简单的尝试是将这 3 个renderer.image { ... }调用合并为一个调用。您应该能够将第二个 2 调用的内容移动到第一个。这应该会产生巨大的性能差异。

除此之外,您真的需要对相机胶卷中的全尺寸图像执行此操作吗?如果没有,请在执行所有不需要的渲染之前调整您在渲染器上设置的大小。

通常,当您尝试以高性能方式进行此类过滤时,您会使用CoreImage. 有了它,您可以非常高速地处理图像。就像过滤实时视频的 60 fps。

我将从查看 Apple 的内置过滤器列表开始: https ://developer.apple.com/library/archive/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html

这是如何使用过滤器的一个很好的例子: https ://www.hackingwithswift.com/articles/204/how-to-use-core-image-filters-the-type-safe-way

如果您发现无法组合内置过滤器来获得效果,您可以随时编写自己的非常简单的 Metal 支持过滤器: https ://flexmonkey.blogspot.com/2016/01/metal- kernel-functions-as-core-image.html


推荐阅读