首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >绘制CIImage太慢了

绘制CIImage太慢了
EN

Stack Overflow用户
提问于 2016-05-26 02:45:18
回答 4查看 7.8K关注 0票数 11

我正在创建一个应用程序,需要实时应用过滤器的图像。将UIImage转换为CIImage和应用过滤器都是非常快的操作,但是要将创建的CIImage转换回CGImageRef并显示图像(1/5秒,如果编辑需要实时的话,这实际上是很多事情)。

图像大小约为2500×2500像素,这很可能是问题的一部分。

目前,我正在使用

代码语言:javascript
复制
let image: CIImage //CIImage with applied filters
let eagl = EAGLContext(API: EAGLRenderingAPI.OpenGLES2)
let context = CIContext(EAGLContext: eagl, options: [kCIContextWorkingColorSpace : NSNull()])

//this line takes too long for real-time processing
let cg: CGImage = context.createCGImage(image, fromRect: image.extent)

我已经研究过使用EAGLContext.drawImage()

代码语言:javascript
复制
context.drawImage(image, inRect: destinationRect, fromRect: image.extent)

然而,我找不到任何关于这件事是如何完成的可靠的文档,或者它是否会更快。

是否有更快的方法将CIImage显示到屏幕上(无论是在UIImageView中还是直接在CALayer上)?我想避免降低太多的图像质量,因为这可能是明显的用户。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-05-27 00:14:10

最后我使用了context.drawImage(image, inRect: destinationRect, fromRect: image.extent)方法。下面是我创建的图像视图类

代码语言:javascript
复制
import Foundation
//GLKit must be linked and imported
import GLKit

class CIImageView: GLKView{
    var image: CIImage?
    var ciContext: CIContext?

    //initialize with the frame, and CIImage to be displayed
    //(or nil, if the image will be set using .setRenderImage)
    init(frame: CGRect, image: CIImage?){
        super.init(frame: frame, context: EAGLContext(API: EAGLRenderingAPI.OpenGLES2))

        self.image = image
        //Set the current context to the EAGLContext created in the super.init call
        EAGLContext.setCurrentContext(self.context)
        //create a CIContext from the EAGLContext
        self.ciContext = CIContext(EAGLContext: self.context)
    }

    //for usage in Storyboards
    required init?(coder aDecoder: NSCoder){
        super.init(coder: aDecoder)

        self.context = EAGLContext(API: EAGLRenderingAPI.OpenGLES2)
        EAGLContext.setCurrentContext(self.context)
        self.ciContext = CIContext(EAGLContext: self.context)
    }

    //set the current image to image
    func setRenderImage(image: CIImage){
        self.image = image

        //tell the processor that the view needs to be redrawn using drawRect()
        self.setNeedsDisplay()
    }

    //called automatically when the view is drawn
    override func drawRect(rect: CGRect){
        //unwrap the current CIImage
        if let image = self.image{
            //multiply the frame by the screen's scale (ratio of points : pixels),
            //because the following .drawImage() call uses pixels, not points
            let scale = UIScreen.mainScreen().scale
            let newFrame = CGRectMake(rect.minX, rect.minY, rect.width * scale, rect.height * scale)

            //draw the image
            self.ciContext?.drawImage(
                image,
                inRect: newFrame,
                fromRect: image.extent
             )
        }
    }   
}

然后,使用它,简单地

代码语言:javascript
复制
let myFrame: CGRect //frame in self.view where the image should be displayed
let myImage: CIImage //CIImage with applied filters

let imageView: CIImageView = CIImageView(frame: myFrame, image: myImage)
self.view.addSubview(imageView)

在将UIImage转换为CIImage之前,将其调整为屏幕大小也有帮助。在高质量图像的情况下,它大大加快了速度。只需确保使用全尺寸的图像时,实际保存它。

就这样!然后,更新视图中的图像。

代码语言:javascript
复制
imageView.setRenderImage(newCIImage)
//note that imageView.image = newCIImage won't work because
//the view won't be redrawn
票数 8
EN

Stack Overflow用户

发布于 2016-05-27 04:16:03

这可能是值得考虑的金属和显示与一个MTKView

您将需要一个可以用MTLCreateSystemDefaultDevice()创建的金属设备。用于创建命令队列和核心图像上下文。这两个对象都是持久的,实例化成本也很高,因此理想情况下应该只创建一次:

代码语言:javascript
复制
lazy var commandQueue: MTLCommandQueue =
{
    return self.device!.newCommandQueue()
}()

lazy var ciContext: CIContext =
{
    return CIContext(MTLDevice: self.device!)
}()

您还需要一个颜色空间:

代码语言:javascript
复制
let colorSpace = CGColorSpaceCreateDeviceRGB()!

当涉及到呈现CIImage时,您需要创建一个短暂的命令缓冲区:

代码语言:javascript
复制
let commandBuffer = commandQueue.commandBuffer()

您将希望将您的CIImage (我们称之为image)呈现为MTKViewcurrentDrawable?.texture。如果这被绑定到targetTexture,则呈现语法是:

代码语言:javascript
复制
    ciContext.render(image,
        toMTLTexture: targetTexture,
        commandBuffer: commandBuffer,
        bounds: image.extent,
        colorSpace: colorSpace)

    commandBuffer.presentDrawable(currentDrawable!)

    commandBuffer.commit()

我有一个工作版本的这里

希望这能帮上忙!

西蒙

票数 16
EN

Stack Overflow用户

发布于 2016-05-26 10:41:19

您可以像使用GlkView ()一样使用context.drawImage和呈现:

代码语言:javascript
复制
let glView = GLKView(frame: superview.bounds, context: EAGLContext(API: .OpenGLES2))
let context = CIContext(EAGLContext: glView.context)

处理后呈现图像:

代码语言:javascript
复制
glView.bindDrawable()
context.drawImage(image, inRect: destinationRect, fromRect: image.extent)
glView.display()
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37450696

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档