代码之家  ›  专栏  ›  技术社区  ›  magohamote

如何在ARKit 1.5中进行初始检测后跟踪图像锚?

  •  3
  • magohamote  · 技术社区  · 8 年前

    我正在努力 ARKit 1.5 通过图像识别和 sample project from Apple : 初始检测后不会跟踪图像定位,因此创建 限制平面可视化显示持续时间的动画。

    ARImageAnchor 没有 center: vector_float3 喜欢 ARPlaneAnchor 我无法找到如何跟踪检测到的图像锚。

    我想在这方面有所成就 video ,也就是说,要有一个固定的图像、按钮、标签等等,保持在检测到的图像的顶部,我不知道如何才能做到这一点。

    以下是图像检测结果的代码:

    // MARK: - ARSCNViewDelegate (Image detection results)
    /// - Tag: ARImageAnchor-Visualizing
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        guard let imageAnchor = anchor as? ARImageAnchor else { return }
        let referenceImage = imageAnchor.referenceImage
        updateQueue.async {
    
            // Create a plane to visualize the initial position of the detected image.
            let plane = SCNPlane(width: referenceImage.physicalSize.width,
                             height: referenceImage.physicalSize.height)
            plane.materials.first?.diffuse.contents = UIColor.blue.withAlphaComponent(0.20)
            self.planeNode = SCNNode(geometry: plane)
    
            self.planeNode?.opacity = 1
    
            /*
             `SCNPlane` is vertically oriented in its local coordinate space, but
             `ARImageAnchor` assumes the image is horizontal in its local space, so
             rotate the plane to match.
             */
            self.planeNode?.eulerAngles.x = -.pi / 2
    
            /*
             Image anchors are not tracked after initial detection, so create an
             animation that limits the duration for which the plane visualization appears.
             */
    
            // Add the plane visualization to the scene.
            if let planeNode = self.planeNode {
                node.addChildNode(planeNode)
            }
    
            if let imageName = referenceImage.name {
                plane.materials = [SCNMaterial()]
                plane.materials[0].diffuse.contents = UIImage(named: imageName)
            }
        }
    
        DispatchQueue.main.async {
            let imageName = referenceImage.name ?? ""
            self.statusViewController.cancelAllScheduledMessages()
            self.statusViewController.showMessage("Detected image “\(imageName)”")
        }
    }
    
    3 回复  |  直到 8 年前
        1
  •  15
  •   rickster    7 年前

    在大多数情况下,您的代码都会在检测到的图像上放置一个平面,因此很明显,您在那里有一些东西可以成功地将平面的中心位置设置为图像锚点的中心位置。也许你的第一步应该是更好地理解你的代码。。。

    ARPlaneAnchor 有一个 center (和 extent )因为飞机在ARKit最初检测到后可以有效增长。当你第一次得到飞机锚时 transform 告诉您平面水平(或垂直)曲面的一些小面片的位置和方向。仅此一点就足以将一些虚拟内容放置在这一小块表面的中间。

    随着时间的推移,ARKit会找出更多相同平面的位置,因此飞机会锚定 程度 变得更大。但您可能会首先检测到(例如)表格的一端,然后再识别出更多的远端,这意味着平坦的曲面并非围绕检测到的第一个面片居中。而不是改变 使改变 ARKit告诉你 居中 (即 相对于 这一转变)。

    ARImageAnchor ARKit不会一次检测到整个图像,或者根本不会检测到图像。因此,当您检测到图像时,锚点 使改变 告诉您图像中心的位置和方向。(如果您想知道大小/范围,可以从 physicalSize ,就像示例代码一样。)

    因此,要在 ARImageAnchor (或任何其他 ARAnchor 子类),您可以:

    • 只需将其添加为 SCNNode ARKit在该委托方法中为您创建。如果不进行更改,则其位置和方向将与拥有它的节点的位置和方向相匹配。(这就是你引用的苹果示例代码所做的。)

    • 将其放置在世界空间中(即,作为场景的子对象 rootNode ),使用锚点 使改变 获得位置或方位或两者兼而有之。

      (您可以从转换矩阵中提取转换,即相对位置:获取最后一列的前三个元素;例如。 transform.columns.3 是一个 float4 其xyz元素为位置且w元素为1的向量。)


    您链接到的演示视频并不是将东西放在3D空间中,而是将2D UI元素放在屏幕上,其位置跟踪世界空间中锚的3D相机相对运动。

    你很容易就能得到 友善的 通过使用 ARSKView (ARKit+SpriteKit)代替 ARSCNView (ARKit+SceneKit)。这样可以将2D精灵与世界空间中的3D位置相关联,然后 ARSKView公司 自动移动和缩放它们,使它们看起来始终附着在这些三维位置上。这是一种常见的3D图形技巧,称为公告牌(billboarding),其中2D精灵始终保持直立并面向相机,但移动和缩放以匹配3D透视。

    如果这就是您想要的效果,那么也有一个应用程序(le示例代码)。这个 Using Vision in Real Time with ARKit 示例主要是关于其他主题,但它 演示如何使用 ARSKView公司 显示与关联的标签的步骤 阿兰乔 职位。(正如您在上面所看到的,放置内容以匹配锚定位置是相同的,无论是哪一个锚定位置 阿兰乔 正在使用的子类。)以下是他们代码中的关键位:

    func view(_ view: ARSKView, didAdd node: SKNode, for anchor: ARAnchor) {
        // ... irrelevant bits omitted... 
        let label = TemplateLabelNode(text: labelText)
        node.addChild(label)
    }
    

    也就是说,只需实现 ARSKView公司 didAdd 委托方法,并添加您想要的任何SpriteKit节点作为ARKit提供的一个节点的子节点。


    然而,演示视频所做的不仅仅是精灵广告牌:它与绘画相关联的标签不仅在2D方向上保持不变,而且在2D大小上保持不变(也就是说,它们不会像广告牌上的精灵那样缩放以模拟透视效果)。更重要的是,它们似乎是UIKit控件,具有全套继承的交互行为,而不仅仅是2D图像,这类图像是使用SpriteKit的方式。

    苹果的API并没有提供一种开箱即用的直接方法来实现这一点,但要想通过某种方式将API片段组合在一起以获得这种结果,这并不难。以下是一些可以探索的途径:

    • 如果不需要UIKit控件,可以在SpriteKit中完成所有操作,使用约束匹配公告牌节点的位置 ARSKView公司 提供但不提供其规模。这可能看起来像这样(未经测试,请注意):

      func view(_ view: ARSKView, didAdd node: SKNode, for anchor: ARAnchor) {
          let label = MyLabelNode(text: labelText) // or however you make your label
          view.scene.addChild(label)
      
          // constrain label to zero distance from ARSKView-provided, anchor-following node
          let zeroDistanceToAnchor = SKConstraint.distance(SKRange(constantValue: 0), to: node)
          label.constraints = [ zeroDistanceToAnchor ]
      }
      
    • 如果需要UIKit元素,请将 ARSKView公司 视图控制器的子视图(不是根视图),并将这些UIKit元素设为其他子视图。然后,在你的SpriteKit场景中 update 方法,检查 阿兰乔 -在下面的节点中,将它们的位置从SpriteKit场景坐标转换为UIKit视图坐标,并相应地设置UIKit元素的位置。(演示似乎使用了弹出窗口,因此您不会将其作为子视图进行管理……您可能正在更新 sourceRect 对于每个popover。)这涉及的内容要多得多,所以细节超出了这个已经很长的答案的范围。


    最后一个注释。。。希望这个冗长的答案对这把钥匙有帮助 问题 您的问题(了解定位点位置并在相机移动时放置跟随它们的三维或二维内容)。

    但要澄清并警告一些关键 文字 在问题的前面:

    当ARKit说检测后它不会跟踪图像时,这意味着它不知道图像何时/是否移动(相对于周围的世界)。ARKit只报告一次图像的位置,因此该位置甚至不会从ARKit如何继续改进对您周围世界和您在其中的位置的估计中受益。例如,如果图像位于墙上,则报告的图像位置/方向可能与墙上的垂直平面检测结果不一致(尤其是随着时间的推移,随着平面估计值的提高)。

    更新时间: 在iOS 12中,您 可以 启用对检测到的图像的“实时”跟踪。但您一次可以跟踪的数量是有限的,因此此建议的其余部分可能仍然适用。

    这并不意味着你不能在世界空间的位置上放置看起来是“跟踪”静态的内容,也就是在屏幕上移动,随着相机的移动而跟随它。

    但这确实意味着,如果您试图做一些依赖于对图像位置进行高精度、实时估计的事情,您的用户体验可能会受到影响。所以,不要试图在你的画周围放置一个虚拟的框架,或者用动画版本来代替这幅画。但是有一个箭头指向的文本标签 粗略地 图像在太空中的位置很好。

        2
  •  1
  •   theMikeSwan    8 年前

    首先,我还没有完全完成您想要做的事情,因此,如果我要实施它,我只会从这里开始

    根据您列出的代码,您正在使用Apple的示例代码来识别AR体验中的图像。该项目设置为使用没有标签、按钮或图像的SceneKit。这意味着您需要使用SpriteKit,它具有可以显示标签和图像的节点。

    这意味着您的第一步是创建一个全新的项目,并选择内容技术设置为SpriteKit的增强现实模板。

    你可以进去看看 resetTracking() 从Apple的图像识别示例了解如何设置图像识别部分。您还需要手动将AR资源文件夹添加到资源目录中,以保存所有参考图像。

    要放置项目,请使用SpriteKit版本的 renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) ,即 view(_ view: ARSKView, didAdd node: SKNode, for anchor: ARAnchor)

    使用Apple的图像识别示例代码,在参考图像的中心添加了新的SceneKit对象,如果图像没有移动,虚拟对象将保持在中心(-ish)。

    我们还知道,我们可以获得参考图像的高度和宽度(如您发布的代码所示)。

    很有可能我们也可以使用SpriteKit和新放置的 SKNode s将以相同的方式结束在检测图像的中心 SCNNode 是的。这意味着我们应该能够创建一个新的 SKNode公司 ( SKSpriteNode 对于图像或 SKLabelNode 对于标签),并将其偏移参考图像高度的一半,以获得图像的顶部中心。一旦节点被放置,它应该看起来像是粘在海报上(ARKit不是完美的,所以会发生一些移动)。

        3
  •  0
  •   Pierre F    6 年前

    iOS 12之后的更新:

    您可以使用 ARImageTrackingConfiguration

    另请参见代码示例 Tracking and Altering Images