没有渲染/虚拟内容的 ARKit/SceneKit 屏幕截图

Posted

技术标签:

【中文标题】没有渲染/虚拟内容的 ARKit/SceneKit 屏幕截图【英文标题】:ARKit/SceneKit Screenshot Without Rendered/Virtual Content 【发布时间】:2018-04-24 18:54:56 【问题描述】:

我有一个非常简单的 ARKit 演示应用程序,我在其中放置了一些带有标签的对象。我目前正在使用ARSCNView 上的snapshot() 函数来获取视频输入的屏幕截图,其中包含我所有渲染的对象。

但是,我想获得一个仅包含原始相机输入的 UIImage,在此之上没有任何额外的渲染对象,最好与屏幕上显示的分辨率相同。我不确定最好的方法是什么。有没有办法剥离渲染的内容?我应该直接绑定到摄像头吗?

目前看起来有点像这样:

class ViewController: UIViewController, ARSCNViewDelegate, ARSessionDelegate 

    @IBOutlet weak var sceneView: ARSCNView!

    var nodeModel:SCNNode!
    ...

    override func viewDidLoad() 
        let scene = SCNScene()
        sceneView.scene = scene
        let modelScene = SCNScene(named: ...
        nodeModel =  modelScene?.rootNode.childNode(...
        ...
        self.view.addSubview( ...
    

    ...some ARKit stuff...some model stuff...


extension ViewController 
    func renderer(_ renderer: SCNSceneRenderer, didRenderScene scene: SCNScene, atTime time: TimeInterval) 
        if self.captureButton.capturing && time > self.captureTime 
            captureScreenshot(scene)            
            self.captureTime = time + TimeInterval(0.1)
        
    

    func captureScreenshot(_ scene: SCNScene)
        DispatchQueue.main.async() 
            let screenshot = self.sceneView.snapshot()
            UIImageWriteToSavedPhotosAlbum(screenshot, nil, nil, nil)
           
    

【问题讨论】:

【参考方案1】:

实现可选的ARSessionDelegate方法:

func session(_ session: ARSession, didUpdate frame: ARFrame)

ARFrame 有一个属性captureImage,它是一个CVPixelBuffer,然后您可以将其转换为UIImage,如下所示:

import VideoToolbox

extension UIImage 
    public convenience init?(pixelBuffer: CVPixelBuffer) 
        var cgImage: CGImage?
        VTCreateCGImageFromCVPixelBuffer(pixelBuffer, nil, &cgImage)

        guard let cgImage = cgImage  else  return nil 
        self.init(cgImage: cgImage)
    

【讨论】:

不错的技巧,但请注意,您不一定需要委托方法来获取框架 - 您也可以从 ARSession 获取 currentFrame,然后您可以从视图中获取. 另请注意该 VideoToolbox 函数的文档中的这一点:源 CVPixelBuffer 可能会在 CGImage 的生命周期内保留。 持有相机系统提供的像素缓冲区是危险,因为相机会从池中回收缓冲区,如果您保留太多缓冲区太久,它将用完它可以使用的缓冲区,从而暂停捕获会话和您的ARSession。如果您将该功能用于屏幕截图,请导出您的 PNG/JPEG/HEIF 图像数据,然后立即丢失 CGImage。 (如果您想在 UI 中显示数据,请根据数据创建新图像。) 这实际上是我昨天找到的确切解决方案,我想我们甚至从同一个地方找到了 UIImage 扩展。 :)

以上是关于没有渲染/虚拟内容的 ARKit/SceneKit 屏幕截图的主要内容,如果未能解决你的问题,请参考以下文章

ARKit + SceneKit:我可以访问帧的分段缓冲区但禁用自动人物遮挡吗?

为 ARKit 请求 3D 模型的指南

将孩子添加到场景 ARKit/SceneKit 时 FPS 下降

Vue 警告客户端渲染的虚拟 DOM 树与服务器渲染的内容不匹配

Nuxt.js 错误:客户端渲染的虚拟 DOM 树与服务器渲染的内容不匹配

[Vue 警告]:客户端渲染的虚拟 DOM 树与服务器渲染的内容不匹配( Nuxt / Vue / lerna monorepo )