因此,我正在制作一款应用程序,其中一些主要功能围绕着将CIFilter应用到图像上。
let context = CIContext()
let context = CIContext(eaglContext: EAGLContext(api: .openGLES3)!)
let context = CIContext(mtlDevice: MTLCreateSystemDefaultDevice()!)
所有这些都使我在CameraView控制器上的CPU使用率(70%)与我对帧应用滤镜和更新图像视图的CPU使用率大致相同。所有这些似乎都是以完全相同的方式工作的,这让我认为我遗漏了一些重要的信息。
例如,使用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
}
差不多就是:
1.从UiImg创建CgImg
1.从CgImg创建CiImg
1.使用上下文应用过滤器并转换回UiImg
1.使用新的UiImg更新任何视图
它在我的iPhone X上运行得很好,在我的iPhone 6上也出人意料地运行得很好。由于我的应用程序非常完整,我希望尽可能地优化它。我已经看了很多关于使用OpenGL和金属来做事情的文档,但似乎想不出如何开始。
我一直认为我是在CPU上运行这些进程,但使用OpenGL和Metals创建上下文并没有带来任何改进。我是否需要使用MetalKit视图或GLKit视图(EaglContext似乎已完全弃用)?我该怎么把这个翻译过来?苹果的文档似乎平淡无奇。
2条答案
按热度按时间4xy9mtcn1#
我开始对此发表评论,但我认为自从WWDC‘18年以来,这是最好的答案。我会以Maven的身份进行编辑,而不是评论,如果这样做是正确的,我愿意删除整个答案。
你在正确的轨道上-当你可以的时候利用图形处理器,它是一个很好的匹配。核心图像和金属,虽然“通常”使用图形处理器的“低级”技术,可以使用CPU,如果需要的话。核心图形?它使用CPU来渲染事物。
图像。
UIImage
和CGImage
是实际图像。然而,CIImage
并非如此。考虑它的最好方法是为一张图片准备一份“食谱”。在使用滤镜时,我通常会坚持使用CoreImage、
CIFilters
、CIImages和GLKViews
。对CI Image使用GLKView意味着使用OpenGL
以及单个CIContext
和EAGLContext
。它提供的性能几乎与使用MetalKit
或MTKViews
一样好。至于使用
UIKit
,它是UIImage
和UIImageView
,我只在需要的时候才使用-保存/分享/上传,无论是什么。在此之前,请坚持使用GPU。……
这是事情开始变得复杂的地方。
Metals是苹果专有的API。因为他们拥有硬件--包括CPU和GPU--他们已经为他们优化了硬件。它的“管道”与OpenGL略有不同。没什么大不了的,只是不同而已。
直到WWDC‘18年,使用
GLKit
,包括GLKView
,都是很好的。但OpenGL的所有功能都被淘汰了,苹果正在将这些东西转移到金属上。虽然(目前)性能提升不是很大,但您最好还是使用MTKView、Metals和CIConext`的新功能。看看@Matt给here的答案,这是一个很好的使用MTKview的方法。
lqfhib0f2#
一些独立的观点:
CGImage
。Core Image的一个主要功能是ability to chain filters,不需要为每个ability to chain filters进行渲染,然后一次渲染所有效果。此外,正如dfd在他的回答中所说,如果您直接渲染到屏幕上,而不是创建一个UIImage
来在图像视图中显示,那会更好。CIFilter
对象。如果参数没有改变,不要每次都重新配置它们。