在RoomPlan会话期间,如何使用ARKit的射线投射将CoreML的 2D Vision边界框准确映射到三维世界坐标?
我正在开发一个iOS 17应用程序,将苹果的 RoomPlan(RoomCaptureSession)与自定义边缘AI模型(通过 CoreML 与 Vision 框架的YOLOv8)实时检测墙面上的结构缺陷(如裂缝)。
架构:
RoomPlan在后台运行,用于生成3D房间网格。- 我截取相机帧(
CVPixelBuffer),并将它们传递给一个VNCoreMLRequest。 - 模型成功返回一个2D的
VNRecognizedObjectObservation(边界框),其坐标为归一化坐标。
挑战:
我需要将这个2D边界框锚定到现实世界中的一个精确的3D绝对坐标(simd_float3),以便缺陷标记与导出的 .usdz 模型和2D .dxf 平面布置图完美对齐。
目前,我将Vision的归一化坐标转换为屏幕坐标,并使用 .estimatedPlane 进行 ARKit 射线投射:
// Pseudo-code of current approach
let screenPoint = CGPoint(x: boundingBox.midX * screenSize.width,
y: (1 - boundingBox.midY) * screenSize.height)
let query = arSession.raycastQuery(from: screenPoint,
allowing: .estimatedPlane,
alignment: .vertical)
if let result = arSession.raycast(query).first {
let worldTransform = result.worldTransform
// Save coordinate...
}
我的问题:
由于RoomPlan自身创建了优化过的墙面(CapturedRoom.Surface),是否更适合对ARKit的 .estimatedPlane进行射线投射,还是有没有办法直接用数学方式与RoomPlan的几何输出相交以获得更高的精度? 在ARSession的世界原点与最终的CapturedRoom导出原点之间,是否存在已知的坐标空间不匹配,需要我在最终的USDZ中处理,以防止3D标记漂移? 对于处理这种跨维度坐标映射的任何见解,将不胜感激。
解决方案
-
先将像素反投影为真实的3D光线。使用
ARFrame.camera.intrinsics(以及simd\_inverse)将Vision的边界框中心转换到相机空间,然后乘以camera.transform得到世界空间的光线。不要仅依赖屏幕宽高比来缩放。 -
对真实几何体进行射线投射,而不是
.estimatedPlane。RoomPlan不断向AR会话输入LiDAR网格。切换到allowing: .existingPlaneGeometry,或遍历ARMeshAnchors /CapturedRoom.Surface.mesh,自行与射线相交。这样能将命中点绑定到实际的墙面上。 -
将坐标空间与RoomPlan的导出对齐。RoomPlan在生成USDZ/DXF之前会重新设定世界原点。缓存
session.currentRoom?.worldTransform(或随CapturedRoom一起提供的重基矩阵),并在写入导出前对你的ARKitworldTransform进行预乘。这样可以防止漂移。 -
可选的简化方法:采样SceneDepth。如果在边界框中心读取
ARFrame.sceneDepth/smoothedSceneDepth,可以直接反投影到一个simd\_float3,无需射线投射。在门框或角落附近,这通常是最稳定的方法。
通过这些步骤,2D检测结果将在世界坐标系中与RoomPlan的 USDZ/DXF对齐。