我正在尝试 ARKit 1.5 进行图片识别,我们可以在sample project from Apple的代码中阅读: 初始检测后不会跟踪图像锚点,因此请创建一个 限制平面可视化显示持续时间的动画。
ARImageAnchor
没有类似center: vector_float3
的{{1}},我找不到如何跟踪检测到的图像锚点。
我想实现像video这样的东西,也就是说,有一个修复图像,按钮,标签,等等,保持在检测到的图像之上,我不明白我怎么能实现这一目标。
以下是图像检测结果的代码:
ARPlaneAnchor
答案 0 :(得分:14)
你已经离开了大部分地方 - 你的代码在检测到的图像上放置了一个平面,所以很明显你有一些东西可以成功地将平面的中心位置设置为图像锚点的位置。也许你的第一步应该是更好地理解你拥有的代码......
ARPlaneAnchor
有一个center
(和extent
),因为在ARKit最初检测到它们后,平面可以有效增长。当你第一次得到一个平面锚时,它的transform
会告诉你一些平坦的水平(或垂直)表面的小块的位置和方向。仅此就足以让您将一些虚拟内容放置在那小块表面的中间。
随着时间的推移,ARKit会计算出更多相同的平面,因此飞机锚extent
变大。但是你最初可能会检测到一个表的一端,然后识别更多的远端 - 这意味着平面不会在检测到的第一个补丁周围。 ARKit不是更改锚点的transform
,而是告诉您新的center
(相对于转换)。
ARImageAnchor
没有增长 - ARKit一次检测到整个图像,或者根本没有检测到图像。因此,当您检测到图像时,锚点transform
会告诉您图像中心的位置和方向。 (如果你想知道大小/范围,你可以从检测到的参考图像的physicalSize
得到它,就像示例代码一样。)
因此,要将一些SceneKit内容放在ARImageAnchor
(或任何其他ARAnchor
子类)的位置,您可以:
只需将其添加为SCNNode
ARKit在该委托方法中为您创建的子节点。如果您没有做某些事情来改变它们,它的位置和方向将与拥有它的节点的位置和方向相匹配。 (这就是您引用的Apple示例代码所做的。)
将其放置在世界空间中(即,作为场景的rootNode
的子项),使用锚点transform
获取位置或方向或两者。
(你可以从变换矩阵中提取平移 - 即相对位置:抓住最后一列的前三个元素;例如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中,您可以启用"直播"跟踪检测到的图像。但是,您可以同时跟踪的数量有限制,因此其他建议可能仍适用。
这并不意味着你不能放置看似“跟踪”静态世界空间位置的内容,就像你在相机移动时在屏幕上移动一样。
但这确实意味着如果您尝试做依赖于对图像位置进行高精度,实时估计的事情,您的用户体验可能会受到影响。所以不要试图在你的绘画周围放置虚拟框架,或者用自己的动画版本替换画面。但是,如果文本标签的箭头指向大致,那么图像在空间中的位置非常棒。
答案 1 :(得分:1)
首先,我还没有完全按照你要做的去做,所以这只是我要开始实施的地方......
根据您列出的代码,您使用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
将以SCNNode
的方式结束在检测到的图像的中心。 。这意味着我们应该能够为图片创建新的SKNode
(SKSpriteNode
或者为标签创建SKLabelNode
)并将其变换偏移参考图像高度的一半以获得图像的顶部中心。一旦放置节点,它应该看起来坚持海报(ARKit不是完美的,所以会发生一点运动)。
答案 2 :(得分:0)