如何将 Vignette CIFilter 应用于 iOS 中的实时摄像头提要?
How to apply a Vignette CIFilter to a live camera feed in iOS?
在 Metal 和 Core Image 的帮助下尝试将简单的晕影滤镜应用于 iPhone6 的原始相机馈送时,我发现处理和渲染的帧之间有很多滞后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()
}
}
}
性能完全不是 Apple 在本文档中提到的:https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/CoreImaging/ci_tasks/ci_tasks.html#//apple_ref/doc/uid/TP30001185-CH3-TPXREF101
我是不是漏掉了什么?
您的第 2 步太慢,无法支持实时渲染...而且您似乎遗漏了几个步骤。为了您的目的,您通常会:
设置:
- 创建
CVPixelBuffer
池 - 使用 CVPixelBufferPoolCreate
- 使用
CVMetalTextureCacheCreate
创建一个金属纹理池
对于每一帧:
- 转换
CMSampleBuffer
> CVPixelBuffer
> CIImage
- 将
CIImage
通过您的过滤器管道
- 将输出图像渲染到
CVPixelBuffer
来自步骤 1 中创建的池中
- 使用
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
class 及其超级 class FilterRenderer
。
在 Metal 和 Core Image 的帮助下尝试将简单的晕影滤镜应用于 iPhone6 的原始相机馈送时,我发现处理和渲染的帧之间有很多滞后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()
}
}
}
性能完全不是 Apple 在本文档中提到的:https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/CoreImaging/ci_tasks/ci_tasks.html#//apple_ref/doc/uid/TP30001185-CH3-TPXREF101
我是不是漏掉了什么?
您的第 2 步太慢,无法支持实时渲染...而且您似乎遗漏了几个步骤。为了您的目的,您通常会:
设置:
- 创建
CVPixelBuffer
池 - 使用CVPixelBufferPoolCreate
- 使用
CVMetalTextureCacheCreate
创建一个金属纹理池
对于每一帧:
- 转换
CMSampleBuffer
>CVPixelBuffer
>CIImage
- 将
CIImage
通过您的过滤器管道 - 将输出图像渲染到
CVPixelBuffer
来自步骤 1 中创建的池中
- 使用
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
class 及其超级 class FilterRenderer
。