- 3D 物体检测跟踪
3D物体检测跟踪技术,是指通过计算机图像处理和人工智能技术对摄像机拍摄到的3D物体识别定位并对其姿态进行跟踪的技术。3D物体跟踪技术的基础也是图像识别,但比前述2D 图像检测、识别、跟踪要复杂得多,原因在于现实世界中的物体是三维的,从不同角度看到的物体形状、纹理都不一样,在进行图像特征值对比时需要的数据和计算比2D 图像大得多。
在 ARKit 中,3D物体检测、识别、跟踪通过预先记录3D物体的空间特征信息,在真实环境中寻找对应的3D真实物体对象,并对其姿态进行跟踪。与2D图像检测跟踪类似,要在 ARKit 中实现 3D 物体检测跟踪也需要一个参考物体库,这个参考物体库中的每个对象都是一个 3D物体的空间特征信息。获取参考物体空间特征信息可以通过扫描真实3D 物体采集其特征信息,生成.arobject 参考物体空间特征信息文件,.arobject 文件只包括参考物体的空间特征信息,而不是参考物体的数字模型,也不能利用该文件复原参考物体三维结构。参考物体空间特征信息对快速、准确检测识别3D物体起着关键作用。
- 获取参考物体空间特征信息
苹果公司提供了一个获取物体空间特征信息的扫描工具,该扫描工具是一个 Xcode 源码工程,需要自已编译,源码名为 Apple's Object Scanner app,读者可自行下载并使用Xcode 编译,下载地址为:https://developer.apple.com/documentation/arkit/scanning_and_detecting_3d_objects。该工具的主要功能是扫描真实世界中的物体并导出.arobject 文件,可作为3D物体检测识别的参考物体。
使用扫描工具进行扫描的过程其实是对物体表面3D特征值信息与空间位置信息的采集过程,这是一个计算密集型的工作,为确保扫描过程流畅、高效,建议使用高性能的iOS设备,当然扫描工作可以在任何支持 ARKit 的设备上进行,但高性能iOS设备可以更好地完成这一任务。
4-6 扫描采集3D 参考物体空间特征信息
参考物体空间特征信息对后续3D物体检测识别速度、准确性有直接影响,因此,正确地扫描并生成.arobject 文件非常重要,遵循下述步骤操作可以提高扫描成功率。下面,引导大家一步一步完成这个扫描过程。
(1)将需要扫描的物体放置在一个背景干净不反光的平整面上(如桌面、地面),运行扫描工具,将被扫描物体放置在摄像头正中间位置,在扫描工具检测到物体时会出现一个空心长方体(包围盒),移动手机/平板,将长方体大致放置在物体的正中间位置,让包围盒框住被扫描物体,如图4-6(a)所示,屏幕上也会提示包围盒的相关信息。但这时包围盒可能与实际物体尺寸不匹配,单击 Next 按钮可调整包围盒大小。
(2)在正式扫描之前需要调整包围盒的大小,扫描工具程序只采集包围盒内的物体空间特征信息,因此,包围盒大小对采集信息的完整性非常关键。围绕着被扫描物体移动手机/平板,扫描工具会尝试自动调整包围盒的大小,如果自动调整结果不是很理想,也可以手动进行调整,方法是长按长方体的一个面,当这个面出现延长线时拖动该面就可以移动该面,长方体6个面都可以采用类似方法进行调整。包围盒不要过大或过小,过小采集不到完整的物体空间特征信息,过大可能会采集到周围环境中的其他物体信息,不利于快速检测识别3D 物体。调鳖好后单击 Scan 按钮开始对物体空间特征信息进行采集,如图4-6(b)所示。
(3)在开始扫描物体后,扫描工具程序会给出视觉化的信息采集提示,通过将成功采集过的区域用淡黄色色块标识出来,引导用户完成全部信息采集工作,如图4-6(c)所示。
(4)缓慢移动手机(保持被扫描物体不动),从不同角度扫描物体,确保包围盒的所有面都成功扫描(通常底面不需要扫描,只需要扫描前、后、左、右、上5个面),如图4-6(d)、扫描工具程序会在所有面的信息采集完后自动进入下一步,或者在采集完所有信息后可以手动单击Finish 按钮进行到下一步,如果在未完整采集到所需信息时单击 Finish则会提示采集信息不足。
4-8 扫描采集3D 参考物体空间特征信息
(5)在采集完物体空间特征信息后,扫描工具程序会在物体上显示一个XY2 的三维彩色坐标轴,如图4-8(a)所示。这个坐标轴的原点表示这个物体的原点(这个原点代表的是模型局部坐标系原点),可以通过拖动3个坐标轴边上的小圆球调整蜜标轴的原点位置。在图4-8(b)中可以看到 load Model按钮(pro机型才有),单击该按钮可以加载一个 USDZ 格式模型文件,加载完后会在三维坐标轴原点显示该模型,就像是在真实环境中检测到3D物体并加载数字模型一样。通过加载模型可以直观看到数字模型与真实三维物体之间的位置关系(贴合程度),如果位置不合适可以重复步骤(5)调整三维坐标轴原点位置,直到加载后的数字模型位置达到预期要求(通过Load Model 按钮可以预先查看 AR 应用运行后.在检测到 3D 物体时加载模型的效果,提供即时的反馈)。
(6)在调整好坐标轴后可以对采集的空间特征信息进行测试验证,击Test按钮进行测试,如图4-8(b)所示。将被扫描物体放置到不同环境、不同的光照条件下,使用手机摄像头从不同角度查看该物体,在否正确检测出物体的位置及姿态。如果验证时出现无法检测识别的问题说明信息采集不完整或者有问题,需要重新采集一次如果验证无问题则可导出使用。导出可以直接单击 Share 按钮导出该单个物体采集的空间特征信息.arobject 格件,如图4-8(c)所示,也可以单击左上角的 Merge Scans 合并多个物体空间特征信息文件,如图4-8(d),可以合并之前采集导出的.arobject 文件,也可以开始新的物体扫描然后合并两次扫描结果。
(7)在单击 Share 按钮后该工具程序会将采集的物体空间特征信息导出为.arobject 文件,在打开的导活框中,如图4-8(c)所示,可以选择不同的导出方式,可以保存到云盘,也可以通过邮件、微信等媒介发也人,还可以通过 AirDrop(隔空投送)的方式直接投送到 Mac 计算机或其他iOS 设备上。
- 3D物体识别跟踪基本操作
在 ARKit 中,3D物体检测、识别、跟踪系统依据参考物体库中的参考物体空间特征信息尝试在周围环境中检测匹配的3D物体并跟踪,与2D 图像识别跟踪类似,3D物体识别跟踪也有一些特定的术语,如表4-1所示。
表4-1 3D物体跟踪术语表
术语 | 描述说明 |
参考物体 (Reference Object) | 识别3D物体的过程也是一个特征值对比的过程,ARKit 将从摄像头中获取的图像信息与参考物体库的参考物体空间特征值信息进行对比,存储在参考物体库中的用于对比的物体空间特征信息就叫作参考物体(物体空间特征信息并不是数字模型,也不能据此恢复出3D物体)。 一旦对比成功,真实环境中的3D物体将与参考物体库的参考物体建立对应关系,每一个真实3D 物体的姿态信息也一并被检测 |
参考物体库 (Reference Object Library) | 参考物体库用来存储一系列参考物体空间特征信息用于对比,每一个3D 物体跟踪程序都必须有一个参考物体库,但需要注意的是,参考物体库中存储的实际是参考物体的空间特征值信息而不是原始3D物体网格信息,这有助于提高对比速度与鲁棒性。参考物体库越大,3D物体检测对比就会越慢,相比 2D 图像检测识别,3D物体检测识别需要比对的数据量更大、计算也更密集,因此,在同等条件下,参考物体库中可容纳的参考物体数量比 2D 图像库中的参考图像数量少得多 |
AR 物体锚点 (ARObject Anchor) | 记录真实世界中被检测识别的3D物体位置与姿态的锚点,该锚点由 ARSession 在检测识别到 3D物体后自动添加到每一个被检测到的对象上。通过该锚点,可以将虚拟物体对象谊染到指定的空间位置上 |
3D物体检测效果,当检测到这个盒子时添加一个虚拟物体
与2D图像检测跟踪一样,在 ARKit 中,3D 物体检测跟踪的使用也分成两步,第一步是建立一个参考物体库(参考物体库也可以在运行时动态建立),第二步是配置好 3D物体跟踪 Configuration 配置,并使用该配置运行 ARSession。具体代码如下:
//
// ObjectChceking.swift
// ARKitDeamo
//
// Created by zhaoquan du on 2024/1/22.
//
import SwiftUI
import ARKit
import RealityKit
struct ObjectChceking: View {
static var arView: ARView?
var body: some View {
ObjectChcekingContainer()
.overlay(
VStack{
Spacer()
Button(action: {ObjectChceking.arView?.changeObjectsLibrary()}) {
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("3D物体检测")
}
}
struct ObjectChcekingContainer: UIViewRepresentable {
var dele = ARViewObjectCheckingDelegate()
func makeUIView(context: Context) -> some ARView {
let arView = ARView(frame: .zero)
guard let images = ARReferenceObject.referenceObjects(inGroupNamed: "ReferenceObjectsLibrary", bundle: Bundle.main) else {
fatalError("无法加载物体")
}
let config = ARWorldTrackingConfiguration()
config.detectionObjects = images
arView.session.run(config,options: [])
arView.session.delegate = dele
ObjectChceking.arView = arView
return arView
}
func updateUIView(_ uiView: UIViewType, context: Context) {
}
}
extension ARView {
func changeObjectsLibrary(){
guard let config = session.configuration as? ARWorldTrackingConfiguration else {
return
}
guard let detectedObjectsLib = ARReferenceObject.referenceObjects(inGroupNamed: "ReferenceObjectLibrary1", bundle: Bundle.main) else {
fatalError("无法加载参考物体")
}
config.maximumNumberOfTrackedImages = 1
config.detectionObjects = detectedObjectsLib
session.run(config, options:[.resetTracking,.removeExistingAnchors])
print("参考物体库切换成功")
}
}
class ARViewObjectCheckingDelegate: NSObject, ARSessionDelegate {
public func session(_ session: ARSession, didAdd anchors: [ARAnchor]){
guard let pAnchor = anchors[0] as? ARObjectAnchor else {
return
}
let objectName = pAnchor.referenceObject.name == "jinhua" ? "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())
ObjectChceking.arView?.scene.addAnchor(objectEntity)
} catch {
print("加载失败")
}
}
}
}
在上述代码中,首先从 bundle 中加载参考物体库,并将该参考物体库设置到 AR 配置类的trackedObjectsLib 属性,然后通过 ARSession.run()方法即可运行3D 物体检测跟踪。ARKit 支持同时跟踪多个3D物体,同时跟踪的物体越多,性能消耗也会越大,在一般情况下,建议同时跟踪的3D物体不多于3个。运行3D 物体检测识别应用后,当 ARKit 检测到与参考物体库中参考物体一致的 3D物体时,ARSession 会自动添加一个 ARObjectAnchor 到 ARAnchor 集合中,开发人员可以通过 ARSessionDelegate协议中的 session(_ session:ARSession, didAdd anchors: [ARAnchor])代理方法进行相应处理。
参考物体库除了可以在 Xcode 编辑状态下静态创建,也可以在AR应用运行时动态创建,典型的参考代码如下:
let arView = ARView(frame: .zero)
let config1 = ARObjectScanningConfiguration()
config1.planeDetection = .horizontal
arView.session.run(config1, options: [.resetTracking])
相关代码地址:https://github.com/duzhaoquan/ARkitDemo.git