因此,我正在开发一个应用程序,其中一些主要功能围绕将CIFilter应用于图像。
let context = CIContext()
let context = CIContext(eaglContext: EAGLContext(api: .openGLES3)!)
let context = CIContext(mtlDevice: MTLCreateSystemDefaultDevice()!)
所有这些在我的CameraViewController上给我大约相同的CPU使用率(70%),在这里我将滤镜应用于帧并更新imageview。所有这些似乎都以完全相同的方式工作,这使我觉得我缺少一些重要的信息。
例如,使用AVFoundation,我从相机获取每个帧,然后应用滤镜并使用新图像更新imageview。
let context = CIContext()
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
connection.videoOrientation = orientation
connection.isVideoMirrored = !cameraModeIsBack
let videoOutput = AVCaptureVideoDataOutput()
videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
let sharpenFilter = CIFilter(name: "CISharpenLuminance")
let saturationFilter = CIFilter(name: "CIColorControls")
let contrastFilter = CIFilter(name: "CIColorControls")
let pixellateFilter = CIFilter(name: "CIPixellate")
let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
var cameraImage = CIImage(cvImageBuffer: pixelBuffer!)
saturationFilter?.setValue(cameraImage, forKey: kCIInputImageKey)
saturationFilter?.setValue(saturationValue, forKey: "inputSaturation")
var cgImage = context.createCGImage((saturationFilter?.outputImage!)!, from: cameraImage.extent)!
cameraImage = CIImage(cgImage: cgImage)
sharpenFilter?.setValue(cameraImage, forKey: kCIInputImageKey)
sharpenFilter?.setValue(sharpnessValue, forKey: kCIInputSharpnessKey)
cgImage = context.createCGImage((sharpenFilter?.outputImage!)!, from: (cameraImage.extent))!
cameraImage = CIImage(cgImage: cgImage)
contrastFilter?.setValue(cameraImage, forKey: "inputImage")
contrastFilter?.setValue(contrastValue, forKey: "inputContrast")
cgImage = context.createCGImage((contrastFilter?.outputImage!)!, from: (cameraImage.extent))!
cameraImage = CIImage(cgImage: cgImage)
pixellateFilter?.setValue(cameraImage, forKey: kCIInputImageKey)
pixellateFilter?.setValue(pixelateValue, forKey: kCIInputScaleKey)
cgImage = context.createCGImage((pixellateFilter?.outputImage!)!, from: (cameraImage.extent))!
applyChanges(image: cgImage)
}
另一个示例是我如何仅对普通图像应用更改(我使用滑块进行所有操作)
func imagePixelate(sliderValue: CGFloat){
let cgImg = image?.cgImage
let ciImg = CIImage(cgImage: cgImg!)
let pixellateFilter = CIFilter(name: "CIPixellate")
pixellateFilter?.setValue(ciImg, forKey: kCIInputImageKey)
pixellateFilter?.setValue(sliderValue, forKey: kCIInputScaleKey)
let outputCIImg = pixellateFilter?.outputImage!
let outputCGImg = context.createCGImage(outputCIImg!, from: (outputCIImg?.extent)!)
let outputUIImg = UIImage(cgImage:outputCGImg!, scale:(originalImage?.scale)!, orientation: originalOrientation!)
imageSource[0] = ImageSource(image: outputUIImg)
slideshow.setImageInputs(imageSource)
currentFilteredImage = outputUIImg
}
非常好:
这在我的iPhone X上运行良好,并且在我的iPhone 6上也运行良好。由于我的应用程序非常完整,因此我希望尽可能地对其进行优化。我浏览了很多有关使用OpenGL和Metal进行处理的文档,但似乎无法弄清楚如何开始。
我一直以为我在CPU上运行这些进程,但是使用OpenGL和Metal创建上下文并没有改善。我是否需要使用MetalKit视图或GLKit视图(eaglContext似乎已完全弃用)?我该如何翻译呢?苹果文件似乎没什么意思。
答案 0 :(得分:1)
我开始对此发表评论,但是我认为自WWDC'18以来,这是最好的答案。我会像其他人一样编辑比我评论的要多的专家,如果愿意的话,我愿意删除整个答案。
您处在正确的轨道上-尽可能使用GPU,这非常合适。 CoreImage和Metal,而“通常”使用GPU的“低级”技术,如果需要,可以使用CPU。 CoreGraphics?它使用GPU 渲染东西。
图像。 UIImage
和CGImage
是实际图像。 CIImage
不是。想到它的最好方法是图像的“配方”。
我通常-现在,我将稍后解释-使用过滤器时,请坚持使用CoreImage,CIFilters
,CIImages和GLKViews
。对CIImage使用GLKView意味着使用OpenGL
以及单个CIContext
和EAGLContext
。与使用MetalKit
或MTKViews
一样,它提供的几乎性能都很好。
对于使用UIKit
以及UIImage
和UIImageView
来说,我只在需要时才做-保存/共享/上传。一直坚持到那时。
....
在这里开始变得复杂。
Metal是Apple专有的API。由于他们拥有硬件(包括CPU和GPU),因此已经对其进行了优化。它的“管道”与OpenGL有所不同。没什么大不了的,只是有所不同。
直到WWDC'18使用GLKit
(包括GLKView
)都可以。但是OpenGL的所有东西都被贬低了,苹果公司正在将它们转移到Metal。尽管目前的性能提升不是那么好,但最好还是使用MTKView,Metal和CIContext`。
看看答案,@ matt给了here一个使用MTKViews的好方法。
答案 1 :(得分:0)
一些独立点:
CGImage
。 Core Image的主要功能是ability to chain filters,无需为每个效果进行渲染,然后立即渲染所有效果。另外,正如dfd在他的回答中所说,如果您直接在屏幕上渲染而不是创建UIImage
以在图像视图中显示,那会更好。CIFilter
对象。如果参数没有更改,请不要每次都重新配置它们。