因此,我正在制作一个应用程序,其中一些主要功能围绕着将CIFilters应用于图像。
let context = CIContext()
let context = CIContext(eaglContext: EAGLContext(api: .openGLES3)!)
let context = CIContext(mtlDevice: MTLCreateSystemDefaultDevice()!)所有这些给了我大约相同的CPU使用率(70%)在我的CameraViewController,在那里我应用过滤器的帧和更新的图像视图。所有这些似乎都是一样的,这让我觉得我错过了一些重要的信息。
例如,使用AVFoundation,我从相机中获取每一帧,应用过滤器并使用新图像更新图像视图。
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)?我怎么把这个翻译完?苹果的文件似乎毫无新意。
发布于 2018-08-19 23:57:22
我开始对此发表评论,但我认为,自从WWDC'18‘以来,这是一个最好的答案。我会编辑更多的专家,而不是我的评论,并愿意删除整个答案,如果这是正确的事情。
你是在正确的轨道-利用GPU时,你可以,这是一个很好的适合。CoreImage和Metal,虽然“通常”使用GPU的“低级”技术,但如果需要的话,可以使用CPU。CoreGraphics?它使用CPU呈现事物。
图像。UIImage和CGImage是实际的图像。然而,CIImage却不是,最好的思考方法是一个图像的“配方”。
我通常--现在,我将解释一下--在使用过滤器时坚持使用CoreImage、CIFilters、CIImages和GLKViews。对GLKView使用CIImage意味着使用OpenGL和单个CIContext和EAGLContext。它提供的性能几乎与使用MetalKit或MTKViews一样好。
至于使用UIKit (它是UIImage和UIImageView ),我只在需要时才这样做--保存/共享/上传,什么的。坚持到那个时候。
……
从这里开始变得复杂起来。
金属是苹果专有的API。因为他们拥有硬件--包括CPU和GPU --他们为他们优化了硬件。它的“管道”与OpenGL略有不同。没什么大不了的,只是不一样。
直到WWDC'18,使用GLKit,包括GLKView,都很好。但是所有的东西OpenGL都被破坏了,苹果公司正在把东西转移到金属上。虽然性能(目前)并不是很好,但最好还是使用MTKView、Metal和CIContext` `。
请看答案:马特给了这里一个很好的使用MTKViews的方法。
发布于 2018-08-20 03:08:15
一些独立的观点:
CGImage。核心图像的一个主要特征是链式过滤器能力不对每个图像进行渲染,然后一次渲染所有的效果。此外,正如dfd在他的回答中所说,如果您直接呈现到屏幕上,而不是创建一个UIImage在图像视图中显示,那就更好了。CIFilter对象。如果参数没有改变,不要每次都重新配置它们。https://stackoverflow.com/questions/51922595
复制相似问题