如何提升ARKit 3.0中的人物遮挡效果

9
我们正在使用ARKit中的人物遮挡制作演示应用程序。由于我们想在最终场景中添加视频,因此我们使用SCNPlane来渲染视频,并使用SCNBillboardConstraint确保它们面向正确的方向。这些视频也是部分透明的,使用SCNMaterial上的自定义着色器(因此同时播放2个视频)。
现在我们有一些问题,其中人的遮挡非常棘手(见图像)。我们用于测试的视频是穿着黑色裤子和裙子的女人(如果您想知道图像中的黑色是什么)。
我们遇到的问题是,遮挡不总是与人对齐(如图所示),并且有时无法正确检测到某人的头发。
现在我们的问题是什么原因导致了这些问题?我们如何改善这些问题,使它们看起来像this?我们目前正在探索是否因为我们使用平面而导致问题,但只是使用SCNBox并不能解决问题。

enter image description here

1个回答

19

更新日期:2023年3月6日


新的深度 API

由于新的高质量 ZDepth 通道,可以在每秒 60 帧的速度下渲染,因此您可以通过 ARKit 3.5 / 6.0 中的新的深度 API 来提高 People OcclusionObject Occlusion 功能的质量。但是,要获取它,您需要一台带有 LiDAR 扫描仪的 iPhone 或 iPad。在 ARKit 3.0 中,除非使用 Metal 或 MetalKit(因此不容易),否则无法改善 People Occlusion 功能。

提示:请注意,RealityKitAR QuickLook 框架也支持 People Occlusion


当您使用人物遮挡功能时,为什么会出现此问题?

这是由于深度数据的本质所致。我们都知道,3D场景的渲染最终图像可以包含5个数字合成主要通道 - 红色绿色蓝色AlphaZDepth

enter image description here

当然,还有其他有用的渲染通道(也称为AOVs)可以用于合成: 法线运动向量点位置UVs视差等等。但在本文中,我们只关注两个主要的渲染集合-RGBAZDepth


在ARKit 3.0中,ZDepth通道有三个严重的缺点


问题1. Z深度的别名和反走样

在任何高端软件(如Nuke、Fusion、Maya或Houdini)中渲染Z深度通道,默认情况下会产生锯齿状边缘或所谓的别名边缘。游戏引擎也不例外-SceneKit、RealityKit、Unity、Unreal或Stingray也存在这个问题。

当然,您可以说在渲染之前我们必须打开一个叫做反走样的功能。是的,它对几乎所有通道都有效,但对于Z深度来说却不是这样。Z深度的问题是-每个前景对象(特别是透明的对象)的边缘像素如果进行了反走样,就会“过渡”到背景对象中。换句话说,FG和BG的像素在FG对象的边缘处混合。

坦白地说,目前在专业合成行业中,只有一种有效的解决深度问题的方法 - Nuke合成师使用Deep channels而不是ZDepth。但是没有一个游戏引擎支持它,因为Deep通道太大了。因此,深度通道合成既不适用于游戏引擎,也不适用于ARKit / RealityKit。唉!

enter image description here


问题2. ZDepth的分辨率

普通的ZDepth通道必须以32位渲染,即使RGBAlpha通道都只有8位。深度数据的32位文件对CPU和GPU来说是一个沉重的负担。ARKit经常在视口中合并几个图层。例如,将真实世界的前景角色与虚拟模型和真实世界的背景角色合成。即使这些图层在视口分辨率而不是真实屏幕分辨率下合成,您是否认为这对您的设备来说太过于繁重?然而,以16位8位渲染ZDepth通道会压缩您真实场景的深度,降低合成的质量。

为了减轻CPU和GPU的负担并节省电池寿命,苹果工程师决定在捕获阶段使用缩小的ZDepth图像,然后将渲染的ZDepth图像放大到视口分辨率,并使用Alpha通道(即分割)对其进行模板,然后使用Dilate合成操作修复ZDepth通道的边缘。因此,这导致我们看到您图片中的这些令人讨厌的伪影(一种“痕迹”)。

enter image description here

enter image description here

请查看《将人们带入AR》的演示幻灯片pdf这里


问题三. ZDepth的帧率

第三个问题源于FPS。ARKit和RealityKit以60 fps的速度运行。缩小ZDepth图像分辨率并不能减少处理量。因此,ARKit 3.0工程师们的下一个逻辑步骤是-将ZDepth的帧率降低到15 fps。然而,最新版本的ARKit和RealityKit以60 fps渲染ZDepth通道,这极大地提高了人物遮挡和物体遮挡的质量。但在ARKit 3.0中,这会导致一些暴露的伪影(一种ZDepth通道的“丢帧”效应,导致“拖尾”效果)。

当您使用此类型属性时,无法更改合成图像的质量:

static var personSegmentationWithDepth: ARConfiguration.FrameSemantics { get }

因为它是一个可获取的属性,并且在ARKit 3.0中没有ZDepth质量的设置。
当然,如果你想提高ARKit 3.0中ZDepth通道的帧率,你应该实现数字合成中发现的“帧插值技术”(其中插入的帧是计算机生成的)。

enter image description here

但是这个帧插值技术需要大量的CPU计算,因为我们需要每秒生成45个额外的32位ZDepth帧(45个插值+15个真实=每秒60帧)。

我相信有人可以使用Metal改进ARKit 3.0中的ZDepth合成功能,但这对开发者来说是一个真正的挑战。请查看People Occlusion in Custom Renderers示例代码


ARKit 6.0和LiDAR扫描仪支持

在ARKit 3.5...6.0中,支持使用LiDAR(光探测与测距扫描仪)。 LiDAR扫描仪提高了People Occlusion功能的质量,因为ZDepth通道的质量更高,即使您在跟踪周围环境时没有实际移动。 LiDAR系统还可以帮助您映射墙壁、天花板、地板和家具,以快速获取用于动态交互的真实世界表面的虚拟网格,或者仅仅是定位它们上面的3D对象(甚至是部分遮挡的虚拟对象)。拥有LiDAR的设备可以实现无与伦比的准确性,检索真实世界表面的位置。通过考虑网格,射线投射可以与非平面表面或没有任何特征的表面相交,例如白色墙壁或几乎没有光照的墙壁。

要激活sceneReconstruction选项,请使用以下代码:

let arView = ARView(frame: .zero)
    
arView.automaticallyConfigureSession = false

let config = ARWorldTrackingConfiguration()

config.sceneReconstruction = .meshWithClassification

arView.debugOptions.insert([.showSceneUnderstanding, .showAnchorGeometry])

arView.environment.sceneUnderstanding.options.insert([.occlusion,
                                                      .collision,
                                                      .physics])
arView.session.run(config)

enter image description here

但在您的代码中使用sceneReconstruction实例属性之前,您需要检查设备是否具有LiDAR扫描仪。您可以在AppDelegate.swift文件中执行此操作:

import ARKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, 
                       didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        guard ARWorldTrackingConfiguration.supportsSceneReconstruction(.meshWithClassification) 
        else {
            fatalError("Scene reconstruction requires a device with a LiDAR Scanner.")
        }            
        return true
    }
}


RealityKit 2.0

使用带有LiDAR的iPhone Pro或iPad Pro上的RealityKit 2.0应用程序时,您有几个遮挡选项-相同的选项在ARKit 6.0中可用-改进的People OcclusionObject Occlusion(例如家具或墙壁)和Face Occlusion。 要在RealityKit 2.0中打开遮挡,请使用以下代码:

arView.environment.sceneUnderstanding.options.insert(.occlusion)

1
我并没有真正期望得到一个更加针对苹果如何改进的答案,但我想你的观点是有道理的。我们只需要等待一段时间,直到他们应用了你的建议(或者直到某个了解Metal和渲染管道的人创建了Metal程序来正确地进行人物遮挡)。 - vrwim
1
您提供的论文表明,深度图像不会抗锯齿深度信息。特别是您的第二个图,似乎是从论文中摘取的,但引用有误。在论文中,图的两侧都代表深度通道,但左侧说明了为什么对深度通道进行抗锯齿处理是没有意义的。 - Vaelus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接