- 2D 图像检测跟踪
图像跟踪技术,是指通过图像处理技术对摄像机中拍摄到的2D 图像进行检测、识别、定位,并对其姿态进行跟踪的技术。图像跟踪技术的基础是图像识别,图像识别是指检测和识别出数字图像或视频中的对象或特征的技术,图像识别技术是信息时代的一门重要技术,其产生的目的是为了让计算机代替人类处理大量的图形图像及真实物体信息,是其他众多技术的基础。
ARKit 具备对2D 图像检测、识别、跟踪的能力,其能实时检测并识别从设备摄像头采集图像中的预定义2D图像,并能评估2D 图像的尺寸大小和稳定跟踪这些图像的姿态,ARKit 最大支持同时跟踪100张2D图像。利用ARKit 的2D 图像检测跟踪功能,可以实现很多有趣的AR 体验,如:
(1)使用2D图像作为放置虚拟元素的参考位置。通常情况下我们会要求用户扫描其周边环境,在检测到的平面上放置虚拟元素,这在某些时候会显得不够友好,如一个零售商店需要显示一个虚拟导购,这时我们可以在商店的大门两侧粘贴两张海报,在ARKit检测到这两张海报后利用这两张海报的位置计算出一个位置显示虚拟导购,营造虚拟导购正在门口迎接顾客的氛围。
(2)使用2D图像作为AR应用入口。AR应用启动后无须检测平面,用户只需要将手机摄像头对准2D图像就可以触发 AR体验,这在某些场合更合适,如在电影院里,用户通过扫描电影海报就可以将电影主角召唤出来。不仅如此,2D 图像检测在教育培训、工业应用等很多场景都有广阔的应用前景。
- 图像检测跟踪基本操作
在ARKit 中,图像跟踪系统依据图像库中的图像信息尝试在现实环境中检测匹配的2D 图像并跟踪它,在 ARKit 的图像跟踪处理中,一些特定的术语如下。
- 参考图像Reference Image) 识别2D 图像的过程实际是一个特征值对比的过程,ARKit 将从摄像头中获取的图像信息与参考图像库的图像特征值信息进行对比,存储在参考图像库中的用于对比的图像就叫作参考图像。一旦对比成功,真实环境中的图像将与参考图像库的参考图像建立对应关系,每一个真实2D 图像的姿态信息也一并被检测
- 参考图像库Refrence Image Library,参考图像库用来存储一系列的参考图像用于对比,每一个图像跟踪程序都必须有一个参考图像库,但需要注意的是,参考图像库中存储的实际是参考图像的特征值信息而不是原始图像,这有助于提高对比速度和鲁棒性。参考图像库越大,图像对比就会越慢,建议参考图像库的图像不要超过25张
- AR 图像锚点RImageAnchor) ARKit 在检测到2D 图像后自动生成一个 ARImageAnchor,包含已检测到图像的空间位置与方向信息,还包括已检测2D 图像的尺寸估计值
ARKit 中,使用图像检测跟踪功能共分成两步:第一步是建立一个参考图像库(参考图像库也可以寸动态建立),第二步是配置好图像跟踪 Configuration,并使用该配置运行 ARSession。面我们使用静态方式创建参考图像库,具体操作如下:
1.新建一个 Xcode 工程,在左侧工程导航面板中选择 Assets. xcassets 文件夹,在打开的资源面板左上右击并打开弹出菜单(或者单击左下角的“+”号),选择 New AR Resource Group 创建一个资源名为 ReferencelmageLibrary,(2).然后往里边添加图片,(3).添加完图片之后在右侧属性面板中,填写图像名,无力尺寸 以及单位。 重复第(2)步和第(3)步,可以在一个参考图像库里添加多张参考图像。为提高检测识别精确ARKit对作为参考图像的图片有很多要求,如果不满足这些要求,则会在参考图像右下角出现一个警示标签,此时可以通过单击这个黄色标签查看原因,并对照原因进行修改,直到满足要求。相关代码如下:
//
// ImageChecking.swift
// ARKitDeamo
//
// Created by zhaoquan du on 2024/1/18.
//
import SwiftUI
import ARKit
import RealityKit
struct ImageChecking: View {
static var arView: ARView?
var body: some View {
ImageCheckingContainer()
.overlay(
VStack{
Spacer()
HStack(spacing: 50){
Button(action: {ImageChecking.arView?.changeObjectsLibrary()}) {
Text("切换图像库")
.frame(width:150,height:50)
.font(.system(size: 17))
.foregroundColor(.black)
.background(Color.white)
.opacity(0.6)
}
.cornerRadius(10)
Button {
ImageChecking.arView?.addReferenceImage()
} label: {
Text("添加图像")
.frame(width: 150, height: 50)
.font(.system(size: 17))
.foregroundColor(.black)
.background(Color.white)
.opacity(0.6)
}
.cornerRadius(10)
}
Spacer().frame(height: 40)
}
)
.edgesIgnoringSafeArea(.all)
.navigationTitle("图像检测")
}
}
struct ImageCheckingContainer: UIViewRepresentable {
var dele = ARViewImageCheckingDelegate()
func makeUIView(context: Context) -> some ARView {
let arView = ARView(frame: .zero)
guard let images = ARReferenceImage.referenceImages(inGroupNamed: "ReferenceImageLibrary", bundle: Bundle.main) else {
fatalError("无法加载图像")
}
let config = ARImageTrackingConfiguration()
config.trackingImages = images
config.maximumNumberOfTrackedImages = 1
config.isAutoFocusEnabled = true//是否自动对焦
arView.session.run(config,options: [])
arView.session.delegate = dele
ImageChecking.arView = arView
return arView
}
func updateUIView(_ uiView: UIViewType, context: Context) {
}
}
extension ARView {
func changeObjectsLibrary(){
let config = session.configuration as! ARImageTrackingConfiguration
guard let detectedObjectsLib = ARReferenceImage.referenceImages(inGroupNamed: "ReferenceImageLibrary1", bundle: Bundle.main) else {
fatalError("无法加载参考物体库")
}
config.maximumNumberOfTrackedImages = 1
config.trackingImages = detectedObjectsLib
session.run(config, options:[.resetTracking,.removeExistingAnchors])
print("参考物体库切换成功")
}
func addReferenceImage(){
guard let config = session.configuration as? ARImageTrackingConfiguration else {return}
guard let image = UIImage(named:"toy_biplane")?.cgImage else { return }
let referenceImage = ARReferenceImage(image,orientation: .up, physicalWidth: 0.15)
config.trackingImages.insert(referenceImage)
session.run(config, options: [])
print("insert image OK")
}
}
class ARViewImageCheckingDelegate: NSObject, ARSessionDelegate {
public func session(_ session: ARSession, didAdd anchors: [ARAnchor]){
guard let pAnchor = anchors[0] as? ARImageAnchor else {
return
}
let objectName = pAnchor.referenceImage.name == "toy_drummer" ? "toy_drummer" : "toy_robot_vintage"
DispatchQueue.main.async {
do{
let myModeEntity = try Entity.load(named: objectName)
let objectEntity = AnchorEntity(anchor: pAnchor)
objectEntity.addChild(myModeEntity)
myModeEntity.playAnimation(myModeEntity.availableAnimations[0].repeat())
ImageChecking.arView?.scene.addAnchor(objectEntity)
} catch {
print("加载失败")
}
}
}
func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
}
}
在上述代码中,首先从 bundle中加载参考图像库,并将该参考图像库设置到 AR配置类的trackinglmages 属性,然后通过 ARSession. run()方法就可以运行2D图像检测跟踪了。ARKit 支持同时跟踪多个 2D图像,通过 maximumNumberOfTrackedimages属性可以设置同时跟踪2D图像的数目,这个債设置得越大,同时跟踪的图像就越多,但性能消耗也会越大。
运行2D 图像检测识别应用后,当ARKit 检测到与参考图像库中参考图像一致的2D图像时,ARSession 会自动添加一个 ARimageAnchor 到 ARAnchor 集合中,开发人员可以通过 ARSessionDelegate协议中的 session(_ session:ARSession,didAdd anchors:[ARAnchor])代理方法进行相应处理。参考图像库除了可以在Xcode 编辑状态下静态创建,也可以在AR应用运行时动态创建,典型的参考代码如代码addReferenceImage
func addReferenceImage(){
guard let config = session.configuration as? ARImageTrackingConfiguration else {return}
guard let image = UIImage(named:"toy_biplane")?.cgImage else { return }
let referenceImage = ARReferenceImage(image,orientation: .up, physicalWidth: 0.15)
config.trackingImages.insert(referenceImage)
session.run(config, options: [])
print("insert image OK")
}
- 检测图像使用的配置
所有 ARConfiguration 配置类的功能都是建立虚拟数字世界与现实物理世界之间的联系,营造虛拟元素的存在于真实世界中的假象。对2D 图像检测跟踪而言,可以使用图像跟踪(ARImageTracking Configuration)世界跟踪(ARWorldTrackingConfiguration)两种配置方式实现。
ARWorldTrackingConfiguration 配置方式可以跟踪现实世界中的所有对象,包括2D图像,通过设置该配置类的以下3个属性,可以实现对2D 图像的检测跟踪:使用 detectionImages 属性设置参考图像库,使用meximumNumberOfTrackedlmages 属性设置最大同时跟踪的图像数量,automaticlmageScaleEstimation Enabled为一个布尔值,用于指示 ARKit 是否对检测到的图像进行尺寸估计。
ARImageTrackingConfiguration 是专为2D 图像检测跟踪优化的配置,其中,trackingImages 属性用于设置参考图像库,maximumNumberOfTrackedImages 设置最大同时跟踪的图像数量,isAutoFocusEnabled为一个布尔值,用于设定对焦方式。
图像跟踪和世界跟踪两种配置类都可以实现对2D 图像的检测跟踪,但通常而言,它们的区别如下:
(1)世界跟踪配置方式比图像跟踪配置方式性能代价更高,因为世界跟踪执行的任务更多,处理的工作量更大,因此,使用图像跟踪配置方式可以检测跟踪更多的2D 图像。
(2) 图像跟踪配置方式只检测跟踪视线内的2D 图像,一旦2D 图像离开视线,对图像的跟踪将不再这行。而世界跟踪 方式会跟踪已检测到的所有图像,即使2D 图像离开视线跟踪也会进行,因此,世界跟踪)式不仅知道2D图像,还知道这个2D 图像所在位置。
(3)世界跟踪方式更适合跟踪静态的、不移动的2D 图像,图像跟踪方式对运动2D 图像跟踪效果会豆好,如跟踪行驶汽车车身上的海报。
在2D图像被检测到之后,ARKit会跟踪该对象的姿态(位置与方向),因此,可以实现虚拟元素与2D目像绑定的效果(即虚拟元素的姿态会随2D 图像的姿态发生变化),如在一张别墅的图片上加载一个虚拟合别墅模型,旋转、移动该别墅图片,虛拟别墅模型也会跟着旋转或者移动,就像虛拟模型黏贴在图片上一样。
- 图像检测优化
为了更好地优化2D 图像检测跟踪,需要从参考图像的选择、参考图像库的设计、整体设计方证考虑。
(1)尽量准确地提供参考图像的物理尺寸,ARKit 依赖这些物理尺寸评估2D 图像到用户设离,不正确的物理尺寸会导致 ARImageAnchor 位置出现偏差,从而影响加载的虛拟模型与2D图人合度。
(2)参考图像应当先在Xcode中进行检测,确保通过Xcode 的评估,如果有警示信息,应当对照参考图像进行完善,高对比度、高特征的参考图像有利于 ARKit 进行图像检测。
(3) 物理图像尽量展平,卷曲的图像,如包裹酒瓶的海报非常不利于 ARKit 检测或者导致检ARImageAnchor 位置错误。
(4)确保需要检测的物理图像照明条件良好,光线昏暗或者反光(如玻璃橱窗里的海报)会影听检测。
(5) 通常情况下,每一个参考图像库的参考图像数量不应该超过25个,如果数量过多会影响性和检测速度。一般情况下,可以将大型的参考图像库拆分为小的参考图像库,然后根据AR应用这条件动态切换参考图像库。
(6) ARKit 对每一个检测到的2D 图像只会触发一次添加 ARImageAnchor 行为,有时我们可食复这个过程,这时可以通过 remove(anchor:)方法移除相应的 ARImageAnchor,这样,当ARKit 再这个2D图像时会再次触发添加 ARImageAnchor 的操作。
具体代码地址: https://github.com/duzhaoquan/ARkitDemo.git