首页 文章

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

提问于
浏览
2

我正在尝试使用图像识别 ARKit 1.5 ,因为我们可以在sample project from Apple的代码中读取:初始检测后不会跟踪图像锚点,因此创建一个限制平面可视化显示持续时间的动画 .

ARImageAnchor 没有像 ARPlaneAnchor 这样的 center: vector_float3 ,我找不到如何跟踪检测到的图像锚点 .

我想实现类似于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)”")
    }
}

2 回答

  • 1

    你已经大部分都在那里 - 你的代码在检测到的图像上放置了一个平面,所以很明显你有一些东西可以成功地将平面的中心位置设置为图像锚点的中心位置 . 也许你的第一步应该是更好地理解你拥有的代码......

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

    随着时间的推移,ARKit计算出更多同一平面的位置,因此平面锚点 extent 变大 . 但是你最初可能会检测到一个表的一端,然后识别更多的远端 - 这意味着平面不会在检测到的第一个补丁周围 . ARKit不是更改锚点的 transform ,而是告诉您新的 center (与该转换相关) .

    ARImageAnchor 不会增长 - 要么ARKit立刻检测到整个图像,要么根本不检测图像 . 因此,当您检测到图像时,锚点 transform 将告诉您图像中心的位置和方向 . (如果你想知道大小/范围,你可以从检测到的参考图像的 physicalSize 得到它,就像示例代码那样 . )

    因此,要将一些SceneKit内容放在 ARImageAnchor (或任何其他 ARAnchor 子类)的位置,您可以:

    • 只需将其添加为 SCNNode ARKit在该委托方法中为您创建的子节点 . 如果您没有做某些事情来改变它们,它的位置和方向将与拥有它的节点的位置和方向相匹配 . (这是您引用的Apple示例代码所做的 . )

    • 将其放置在世界空间中(即,作为场景的子节点 rootNode ),使用锚点 transform 获取位置或方向或两者 .

    (你可以从变换矩阵中提取平移 - 即相对位置: grab 最后一列的前三个元素;例如,transform.columns.3是一个float4向量,其xyz元素是你的位置,其w元素是1 . )


    您链接到的演示视频并没有把东西放在3D空间中 - 它将2D UI元素放在屏幕上,其位置跟踪3D摄像机在世界空间中相对移动的锚点 .

    您可以使用 ARSKView (ARKit SpriteKit)代替 ARSCNView (ARKit SceneKit)轻松获得这种效果(初步近似) . 这使您可以将2D精灵与世界空间中的3D位置相关联,然后 ARSKView 自动移动并缩放它们,使它们看起来保持与这些3D位置的连接 . 这是一种常见的3D图形技巧,称为“广告牌”,其中2D精灵始终保持直立并面向相机,但移动并缩放以匹配3D透视 .

    如果那是您正在寻找的效果,那么也有一个应用程序(示例代码) . Using Vision in Real Time with ARKit示例主要是关于其他主题,但它确实显示如何使用 ARSKView 显示与 ARAnchor 位置关联的标签 . (正如您在上面所看到的,无论您正在使用哪个 ARAnchor 子类,放置匹配锚位置的内容都是相同的 . )这是他们代码中的关键位:

    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相关 .

    Apple的API没有直接提供“开箱即用”的方法,但想象一下将API组合在一起以获得这种结果的方式并不是一件容易的事 . 以下是一些探索途径:

    • 如果您不需要UIKit控件,您可以在SpriteKit中完成所有操作,使用约束来匹配“billboarded”节点的位置 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 方法中,浏览 ARAnchor -以下节点,将其位置从SpriteKit场景坐标转换为UIKit视图坐标,并相应地设置UIKit元素的位置 . (该演示似乎是使用弹出窗口,所以那些你不会作为子视图进行管理......你可能会为每个弹出窗口更新sourceRect . )这涉及更多,所以细节超出了范围这已经很久了 .

    最后一点......希望这个冗长的答案对你的问题的关键问题有所帮助(理解锚定位置并在摄像机移动时放置跟随它们的3D或2D内容) .

    但要澄清并在问题的早期就某些关键词发出警告:

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

    更新:在iOS 12中,您可以启用对搜索到的图像的“实时”跟踪 . 但是,您可以同时跟踪多少人有限制,因此其他建议可能仍然适用 .

    这并不意味着你不能放置看似“跟踪”静态世界空间位置的内容,就像你在相机移动时在屏幕上移动一样 .

    但它确实意味着如果您尝试做依赖于对图像位置进行高精度,实时估计的事情,您的用户体验可能会受到影响 . 所以不要试图在你的绘画周围放置虚拟框架,或者用自己的动画版本替换画面 . 但是,带有箭头的文本标签大致指向图像在空间中的位置是很棒的 .

  • 12

    首先,我还没有完全按照你要做的去做,所以这只是我要开始实现它的地方......

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

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

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

    对于项目的放置,您将使用 renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 的SpriteKit版本,即 view(_ view: ARSKView, didAdd node: SKNode, for anchor: ARAnchor) .

    使用Apple的图像识别示例代码,新的SceneKit对象被添加到参考图像的中心,并且如果虚拟对象停留在中心(-ish),图像不会被移动 .

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

    我们可以通过SpriteKit获得参考图像的尺寸,并且新放置的 SKNode s将以与检测到的图像相同的方式结束. SCNNode s . 这意味着我们应该能够创建一个新的 SKNodeSKSpriteNode 用于图像或 SKLabelNode 用于标签)并将其偏移's transform by one half the reference images height to get the top center of the image. Once the node is placed it should appear to stick to the poster (ARKit isn' t完美所以会有一点运动那个会发生) .

相关问题