人形遮挡简介
在 AR系统中,计算机通过对设备摄像头采集的图像进行视觉处理和组织,建立起实景空间,然后将生成的虚拟对象依据几何一致性原理嵌入到实景空间中,形成虚实融合的增强现实环境,再输出到显示系统中呈现给使用者。
正确实现虚拟物体与真实环境的遮挡关系,需要基于对真实环境3D结构的了解,感知真实世界的3D结构、重建真实世界的数字3D模型,然后基于深度信息实现正确的遮挡。但真实世界是一个非常复杂的3D 环境,精确快速地感知周围环境,建立一个足够好的真实世界3D模型非常困难,特别是在不使用其他传感器的情况下(如结构光、TOF、双目、激光等)。
随着移动设备处理性能的提高、新型传感设备的发明、新型处理方式的出现,虚实遮挡融合的问题也在逐步得到改善。在 ARKit3 中,苹果公司通过神经网络引入了人形遮挡功能,通过对真实场景中人体的精确检测识别,实现虚拟物体与人体的正确遮挡,虚拟物体可以被人体所遮挡,提升了 AR使用体验。
人形遮挡原理
遮挡问题在计算机图形学中其实就是深度排序问题。在AR初始化成功后,场景中所有的虚拟物体都有一个相对于 AR 世界坐标系的坐标,包括虚拟摄像机与虚拟物体,因此,图形渲染管线通过深度缓冲区(Depth Buffer)可以正确地渲染虚拟物体之间的遮挡关系。但是,从摄像机输人的真实世界图像数据并不包含深度信息,无法与虚拟物体进行深度对比。
为解决人形遮挡问题,ARKit 借助于神经网络技术将人体从背景中分离出来,并将分离出来的人体图像保存到新增加的人体分隔缓冲区(Segmentation Buffer)中,人体分隔缓冲区是一个像素级缓冲区,可以精确地将人体与环境区分开来,因此,通过人体分隔缓冲区,可以得到精确的人形图像数据。但仅仅将人体从环境中分离出来还不够,还是没有人体的深度信息,为此,ARKit 又新增一个深度估计缓冲区(EstimatedDepth Data Buffer),这个缓冲区用于存储人体的深度信息,但这些深度信息从何而来呢?借助A12及以上仿生处理器的强大性能及神经网络技术,ARKit 工程师们设计了一个只从输人的 RGB 图像估算人体深度信息的算法,这个深度信息每帧都进行更新。至此,通过 ARKit 既可以从人体分隔缓冲区得到人体区域信息,也可以通过深度估计缓冲区得到人体深度信息,图形渲染管线就可以正确地实现虚拟物体与人体的遮挡。
人形遮挡实现
人形遮挡的实现技术非常复杂,对计算资源要求也非常高,但在 ARKit 中使用该技术实现人形遮挡却非常简单。在 AR 应用中使用人形遮挡需要使用 ARWorld TrackingConfiguration 配置类,并设置其 frameSemantics值为 personSegmentation 或者 personSegmentation WithDepth 之—。当使用 personSegmentation 时,ARKit 不会估算检测到人形的深度信息,人形会无条件遮挡虚拟元素而不管虚拟元素远近。当使用 personSegmentation WithDepth 时,ARKit 在检测到人体时,不仅会分离出人形,还会计算人体到摄像机的距离,从而实现正确的人形遮挡。需要注意的是,只有A13及以上处理器才支持人形遮挡功能,因此在使用前需要先检查设备是否支持。人形遮挡的基本使用方法代码如下所示。
//
// HumanOcclusion.swift
// ARKitDeamo
//
// Created by zhaoquan du on 2024/2/4.
//
import SwiftUI
import ARKit
import RealityKit
import Combine
//HumanExtraction
struct HumanOcclusionView: View {
var body: some View {
HumanOcclusionContainer().edgesIgnoringSafeArea(.all).navigationTitle("人形遮挡")
}
}
struct HumanOcclusionContainer: UIViewRepresentable {
func makeUIView(context: Context) -> ARView {
let arView = ARView(frame: .zero)
guard ARWorldTrackingConfiguration.supportsFrameSemantics(.personSegmentationWithDepth) else {
print("不支持人形遮挡")
return arView
}
let config = ARWorldTrackingConfiguration()
config.frameSemantics = .personSegmentationWithDepth
config.planeDetection = .horizontal
loadModel(arView: arView)
arView.session.run(config)
return arView
}
func updateUIView(_ uiView: ARView, context: Context) {
}
func loadModel(arView: ARView){
var cancelable : AnyCancellable?
cancelable = Entity.loadAsync(named: "fender_stratocaster.usdz").sink(
receiveCompletion: { completion in
if case let .failure(error) = completion {
print("无法加载模型,错误:\(error.localizedDescription)")
}
cancelable?.cancel()
}, receiveValue: { entity in
let planAnchor = AnchorEntity(plane: .horizontal)
planAnchor.addChild(entity)
arView.scene.addAnchor(planAnchor)
cancelable?.cancel()
})
}
}
编译运行,在检测到的平面上放置虚拟物体,当人从虚拟物体前面或后面经过时会出现正确的虚实遮挡,AR虚拟物体不会再漂浮于环境之上,可信度大幅提升。
ARKit 对完整人形检测遮挡效果表现很好,除此之外,对人体局部肢体,如手、脚也有比较好的检测识别和遮挡效果,如图所示。从图中可以看到,ARKit 对人形的区分还是比较精确的,当然,由于深度信息是由神经网络估计得出,而非真实的深度值,所以也会出现深度信息不准确、边缘区分不清晰的问题。
具体代码地址:GitHub - duzhaoquan/ARkitDemo