【问题标题】:Detect a object using camera and position a 3D object using ARKit in iOS在 iOS 中使用相机检测对象并使用 ARKit 定位 3D 对象
【发布时间】:2020-03-18 14:19:22
【问题描述】:

我在寻找什么?

我的要求的简单解释是这样的

  1. 使用 ARKit,使用 iPhone 摄像头检测物体
  2. 在此虚拟空间中查找此对象的位置
  3. 使用 SceneKit 在这个虚拟空间上放置一个 3D 对象。 3D 对象应位于 标记。

一个例子是使用相机检测 3D 空间中的小图像/标记位置,在虚拟空间中的该标记后面放置另一个 3D 球模型(这样球将对用户隐藏,因为标记/图像在前)

到目前为止我能做什么?

  1. 我能够使用 ARKit 检测标记/图像
  2. 我可以在屏幕上放置一个球的 3D 模型。

我的问题是什么?

我无法将球定位在检测到的标记后面。

当球在标记前面时,球正确地隐藏了标记。您可以在侧视图中看到球在标记的前面。见下文

但是当球在标记后面时,不会发生相反的情况。球总是看到前面挡住了标记。我预计标记会隐藏球。所以场景不尊重球位置的 z 深度。见下文

代码

请同时查看 cmets

override func viewDidLoad() {
    super.viewDidLoad()

    sceneView.delegate = self
    sceneView.autoenablesDefaultLighting = true

    //This loads my 3d model.
    let ballScene = SCNScene(named: "art.scnassets/ball.scn")
    ballNode = ballScene?.rootNode

    //The model I have is too big. Scaling it here.
    ballNode?.scale = SCNVector3Make(0.1, 0.1, 0.1)
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    //I am trying to detect a marker/image. So ImageTracking configuration is enough
    let configuration = ARImageTrackingConfiguration()

    //Load the image/marker and set it as tracking image
    //There is only one image in this set
    if let trackingImages = ARReferenceImage.referenceImages(inGroupNamed: "Markers",
                              bundle: Bundle.main) {
        configuration.trackingImages = trackingImages
        configuration.maximumNumberOfTrackedImages = 1
    }

    sceneView.session.run(configuration)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    sceneView.session.pause()
}


func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
    let node = SCNNode()

    if anchor is ARImageAnchor {
        //my image is detected
        if let ballNode = self.ballNode {

            //for some reason changing the y position translate the ball in z direction
            //Positive y value moves it towards the screen (infront the marker)
            ballNode.position = SCNVector3(0.0, -0.02, 0.0)

            //Negative y value moves it away from the screen (behind the marker)
            ballNode.position = SCNVector3(0.0, -0.02, 0.0)
            node.addChildNode(ballNode)
        }
    }

    return node
}

如何让场景尊重z位置?或者换句话说,如何在使用 ARKit 框架检测到的图像/标记后面显示 3D 模型?

我正在使用 Xcode 10.3 针对 iOS 12 运行。让我知道是否需要任何其他信息。

【问题讨论】:

    标签: ios swift scenekit augmented-reality arkit


    【解决方案1】:

    要实现这一点,您需要在 3D 场景中创建一个遮挡物。由于ARReferenceImage 具有physicalSize,因此在创建ARImageAnchor 时在场景中添加几何图形应该很简单。

    几何图形将是 SCNPlaneSCNMaterial,适用于遮挡物。我会选择SCNLightingModelConstant 照明模型(这是最便宜的,我们实际上不会绘制平面),colorBufferWriteMask 等于SCNColorMaskNone。对象应该是透明的,但仍然写入深度缓冲区(这就是它充当遮挡物的方式)。

    最后,通过将其 renderingOrder 设置为 -1(如果应用已经使用渲染命令,则设置更低的值),确保遮挡物在任何增强对象之前渲染。

    【讨论】:

      【解决方案2】:

      在 ARKit 3.0 中,Apple 工程师实施了称为 People Occlusion 的 ZDepth 合成技术。此功能仅在配备 A12 和 A13 的设备上可用,因为它是高度处理器密集型的。目前 ARKit ZDepth 合成功能还处于起步阶段,因此它只允许您合成背景上下(或类似人的对象)的人,而不是通过后置摄像头看到的任何其他对象。而且,我想,你知道前置 TrueDepth 摄像头——它用于面部跟踪,它有额外的红外传感器来完成这项任务。

      要打开 ZDepth 合成功能,请在 ARKit 3.0 中使用这些实例属性:

      var frameSemantics: ARConfiguration.FrameSemantics { get set }
      
      static var personSegmentationWithDepth: ARConfiguration.FrameSemantics { get }
      

      真正的代码应该是这样的:

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

      在 alpha 通道分割后,每个通道的计算公式如下所示:

      r = Az > Bz ? Ar : Br
      g = Az > Bz ? Ag : Bg
      b = Az > Bz ? Ab : Bb
      a = Az > Bz ? Aa : Ba
      
      • 其中 Az 是前景图像的 ZDepth 通道(3D 模型)
      • Bz 是 ZDepth 一个通道的背景图像(2D 视频)
      • Ar、Ag、Ab、Aa – 3D 模型的红色、绿色、蓝色和 Alpha 通道
      • Br、Bg、Bb、Ba – 2D 视频的红色、绿色、蓝色和 Alpha 通道

      但在 ARKit 的早期版本中,没有 ZDepth 合成功能,因此您可以仅使用标准 4 通道合成在 2D 背景视频上合成 3D 模型OVER operation

      (Argb * Aa) + (Brgb * (1 - Aa))
      
      • 其中 Argb 是前景 A 图像(3D 模型)的 RGB 通道

      • Aa 是 Foreground A 图像的 Alpha 通道(3D 模型)

      • Brgb 是背景 B 图像(2D 视频)的 RGB 通道

      • (1 - Aa) 是前景 Alpha 通道的反转

      因此,如果没有 personSegmentationWithDepth 属性,您的 3D 模型将始终是 OVER 2D 视频。

      因此,如果视频上的对象看起来不像人的手或人体,则在使用常规 ARKit 工具时,您无法将 2D 视频中的对象放置在 3D 模型上。

      .....

      不过,您可以使用 MetalAVFoundation 框架来实现。考虑一下——这并不容易。

      要从视频流中提取 ZDepth 数据,您需要以下实例属性:

      // Works from iOS 11
      var capturedDepthData: AVDepthData? { get }
      

      或者您可以使用这两个实例方法(记住 ZDepth 通道必须是 32 位):

      // Works from iOS 13
      func generateDilatedDepth(from frame: ARFrame, 
                             commandBuffer: MTLCommandBuffer) -> MTLTexture
      
      func generateMatte(from frame: ARFrame, 
                      commandBuffer: MTLCommandBuffer) -> MTLTexture
      

      如果您想知道如何使用 Metal 来做到这一点,请阅读 this SO post

      更多信息,请阅读this SO post

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-12-20
        • 2018-01-30
        • 1970-01-01
        • 2017-11-15
        • 1970-01-01
        • 2016-02-17
        • 2018-01-11
        • 2019-03-15
        相关资源
        最近更新 更多