ARKit 人物遮挡示例是如何实现的?

3

这可能是一个晦涩的问题,但我在网上看到很多人使用ARKit 3中的新技术——人体遮挡技术,有效地将人与背景“分离”,并对“人”应用某种过滤器以展示非常酷炫的样例(请参见此处)。

通过查看苹果提供的源代码和文档,我发现我可以从ARFrame中检索出segmentationBuffer,就像下面这样做的:

func session(_ session: ARSession, didUpdate frame: ARFrame) {
    let image = frame.capturedImage
    if let segementationBuffer = frame.segmentationBuffer {

        // Get the segmentation's width
        let segmentedWidth = CVPixelBufferGetWidth(segementationBuffer)

        // Create the mask from that pixel buffer.
        let sementationMaskImage = CIImage(cvPixelBuffer: segementationBuffer, options: [:])

        // Smooth edges to create an alpha matte, then upscale it to the RGB resolution.
        let alphaUpscaleFactor = Float(CVPixelBufferGetWidth(image)) / Float(segmentedWidth)
        let alphaMatte = sementationMaskImage.clampedToExtent()
            .applyingFilter("CIGaussianBlur", parameters: ["inputRadius": 2.0)
            .cropped(to: sementationMaskImage.extent)
            .applyingFilter("CIBicubicScaleTransform", parameters: ["inputScale": alphaUpscaleFactor])

        // Unknown...

    }
}

在“未知”部分,我正在尝试确定如何在原始相机反馈的基础上呈现我的新“模糊”人物。似乎没有任何方法可以在原始相机反馈的“顶部”绘制新的CIImage,因为ARView没有手动更新的方式。
2个回答

5
在下面的代码片段中,我们看到了用于深度合成的personSegmentationWithDepth类型属性(包括RGB、Alpha和深度通道):
// Automatically segmenting and then compositing foreground (people), 
// middle-ground (3D model) and background.

let session = ARSession()

if let configuration = session.configuration as? ARWorldTrackingConfiguration {
    configuration.frameSemantics.insert(.personSegmentationWithDepth)
    session.run(configuration)
}

您可以手动访问CVPixelBuffer中的世界跟踪深度数据(执行分割的深度值):

let image = frame.estimatedDepthData

你可以手动访问CVPixelBuffer中的人脸跟踪深度数据(来自TrueDepth相机):

let image = session.currentFrame?.capturedDepthData?.depthDataMap

此外,在 ARKit 3.0 中还有一个名为 generateDilatedDepth 的实例方法,与此相关的是 IT 技术。
func generateDilatedDepth(from frame: ARFrame, 
                       commandBuffer: MTLCommandBuffer) -> MTLTexture

在您的情况下,您必须使用estimatedDepthData,因为苹果文档中指出:

这是一个缓冲区,代表了从相机获取的估计深度值,您可以使用它来遮挡虚拟内容。

var estimatedDepthData: CVPixelBuffer? { get }

如果你想获得惊人的效果,可以使用合成技术将这个缓冲区中的 DEPTH 数据(首先必须要将深度通道转换为RGB)与RGB或者ALPHA进行相乘。

看看这6个图像:下面一行代表使用深度通道校正过的三个RGB图像: 深度分级、深度模糊和深度点位置通道。

enter image description here


感谢您的回复,@ARGeo。然而,这并没有解释我如何使用segmentationBuffer/depth数据映射。如果我想通过CIFilter运行分割后的人物,然后在屏幕上呈现,我不确定我该如何实现问题中链接的示例视频所实现的效果。 - ZbadhabitZ
1
非常非常有用,@ARGeo。我实际上不知道如何使用估计的深度数据与分割缓冲区相结合,这确实澄清了两者的目的。话虽如此,假设我成功将深度数据转换为RGB,我仍然不清楚如何实际“叠加”我的过滤缓冲区在视图之上。在ARSession中,ARView由iOS预配置,并且似乎没有任何手动更新视图的方法;从某种意义上说,我正在获取相机看到它们和它们被渲染之间的缓冲区;我该如何渲染? - ZbadhabitZ
对于图层叠加,请使用CISourceOverCompositing(它使用公式-Argb * Aa + Brgb *(1-Aa),其中A表示前景,B表示背景)。关于更新视图,我无法发表任何意见,因为我目前无法安装iOS13,所以无法测试任何方法。 - Andy Jazz
其中,Argb*Aa 是预乘的 RGBA 图像,而 (1-Aa) 则是前景图像 alpha 值的反转(alpha 反转会在背景图像中形成一个孔洞,使您可以将一个预乘的前景图像放置到这个孔洞中)。 - Andy Jazz
1
感谢您提供所有详细信息,@ARGeo。您的解释对于理解各种通道正在执行的操作以及如何正确计算它们确实有很大帮助。非常感谢!CISourceOverCompositing也很有用,我觉得这是缺失部分的50%。现在,我必须弄清楚如何将组合图像实际显示在屏幕上,因为我仍然缺乏将组合的CIImage(或CVPixelBuffer)放置在ARFrame之上的知识。 - ZbadhabitZ

2

3
谢谢,@mnuages。我确实看了那个会话以及你提供的示例代码,但我不太确定如何将它们组合起来。该项目中的示例代码引用了构建自己的渲染器来为ARSession绘制分割人和摄像头图像,需要使用Metal。是否有一种方法可以在不使用自定义渲染器的情况下实现相同的效果,仅通过使用segmentationBuffer和estimatedDepthData来修改ARView?而不是构建自己的MTKView? - ZbadhabitZ
这正是我的问题。有关于此的任何更新吗? - Friendly King
也想知道是否有答案来回答这个问题,例如,使用ARFrame作为输入到您的遮挡/渲染系统。 - KFDoom

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