如何将 Vignette CIFilter 应用于 iOS 中的实时摄像机源?

Posted

技术标签:

【中文标题】如何将 Vignette CIFilter 应用于 iOS 中的实时摄像机源?【英文标题】:How to apply a Vignette CIFilter to a live camera feed in iOS? 【发布时间】:2019-05-22 18:03:06 【问题描述】:

在尝试将简单的晕影滤镜应用于 iPhone6 的原始相机馈送时,在 Metal 和 Core Image 的帮助下,我发现在 MTKView 中处理和渲染的帧之间存在很多延迟

我遵循的方法是(MetalViewController.swift):

    使用AVCaptureVideoDataOutputSampleBufferDelegate 获取原始相机输出 转换CMSampleBuffer > CVPixelBuffer > CGImage 用这个CGImage 创建一个MTLTexture

点数2 和 3 在名为:fillMTLTextureToStoreTheImageData

的方法内
    CIFilter 应用于从MTKViewDelegate 中的MTLTexture 获取的CIImage
    func draw(in view: MTKView) 

        if let currentDrawable = view.currentDrawable 
            let commandBuffer = self.commandQueue.makeCommandBuffer()

            if let myTexture = self.sourceTexture

                let inputImage = CIImage(mtlTexture: myTexture, options: nil)

                self.vignetteEffect.setValue(inputImage, forKey: kCIInputImageKey)

                self.coreImageContext.render(self.vignetteEffect.outputImage!, to: currentDrawable.texture, commandBuffer: commandBuffer, bounds: inputImage!.extent, colorSpace: self.colorSpace)

                commandBuffer?.present(currentDrawable)

                commandBuffer?.commit()
            
        
    

性能完全不是苹果在这个文档中提到的:https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/CoreImaging/ci_tasks/ci_tasks.html#//apple_ref/doc/uid/TP30001185-CH3-TPXREF101

我错过了什么吗?

【问题讨论】:

我对相机部分一无所知,但这里有一个基于金属的快速晕影滤镜:github.com/mattneub/Programming-ios-Book-Examples/blob/master/… @matt 我想我已经在没有金属的情况下实现了这一点。仅通过 Core Image 本身将 CIFiilter 应用于图像非常快。当我们尝试处理视频中的每个原始帧时,事情就会失控。为了解决这个问题,我使用了金属,但它没有按预期工作。 也许金属在这里是一个红鲱鱼。 Apple 有示例代码展示了如何将 CIFilter 效果应用于视频,尽管我倾向于怀疑它是否可以跟上 live 视频。 如果您看到我的问题中的链接,苹果明确表示实时渲染实时帧需要金属或 opengl。我遵循了相同的步骤。但我认为苹果提供了一个非常基本的实现,忽略了性能和开销 是的,这可能是真的。我只能找到关于这个主题的 FunHouse 示例代码和 WWDC 2013 session 509 视频。 【参考方案1】:

您的第 2 步太慢了,无法支持实时渲染……而且您似乎遗漏了几个步骤。出于您的目的,您通常会:

设置:

    创建一个CVPixelBuffer 池 - 使用CVPixelBufferPoolCreate 使用CVMetalTextureCacheCreate创建一个金属纹理池

对于每一帧:

    转换CMSampleBuffer > CVPixelBuffer > CIImageCIImage 通过过滤器管道传递 将输出图像渲染到步骤 1 中创建的池中的CVPixelBuffer 使用CVMetalTextureCacheCreateTextureFromImage 使用过滤后的 CVPixelBuffer 创建金属纹理

如果设置正确,所有这些步骤将确保您的图像数据保留在 GPU 上,而不是从 GPU 传输到 CPU 再返回到 GPU 进行显示。

好消息是所有这些都在 Apple https://developer.apple.com/library/archive/samplecode/AVCamPhotoFilter/Introduction/Intro.html#//apple_ref/doc/uid/TP40017556 的 AVCamPhotoFilter 示例代码中进行了演示。尤其是RosyCIRenderer 类及其超类FilterRenderer

【讨论】:

感谢您的指导。一个问题,当您说“所有这些步骤将确保您的图像数据保留在 GPU 上,而不是从 GPU 传输到 CPU 再返回到 GPU 进行显示”时,您是如何识别的?据我所知,MTLDevice 代表 GPU 操作/计算,因此我认为将我的 CGImage 发送到 MTLTexture 并在 draw 委托中获取该 MLTexture 将有助于提高性能。 恐怕“将输出图像渲染成CVPixelBuffer”你必须使用ciContext.render(ciImage, to: pixelBuffer),并且这段代码在CPU中运行

以上是关于如何将 Vignette CIFilter 应用于 iOS 中的实时摄像机源?的主要内容,如果未能解决你的问题,请参考以下文章

应用 CIFilter 后图像旋转

应用 CIFilter 后,无论我做啥,图像都会变大

应用CIFilter后无论我做什么,图像都变大了

在 CALayer 上应用两个以上 CIFilter

金属版 CIFilter 是不是可用于 A7 处理器

如何使用 CIFilter 在 Swift 中将 UIImage 转换为灰度?