如何解决来自 ARKit 深度缓冲区的 SceneKit 点云
我试图在 SceneKit 中找到一种简单的方法来计算 SceneKit 和 LiDAR 数据中的像素深度
sceneView.session.currentFrame?.smoothedSceneDepth?.depthMap
理想情况下,我不想使用金属着色器。我更喜欢在我的 currentFrame
及其对应的深度图中找到一个点,以获取 SceneKit 中点的深度(理想情况下在世界坐标中,而不仅仅是在那个时间点的那个视锥体的局部)。
不需要快速性能,因为它不会在捕获时计算。
我知道 link 的 Apple 项目,但是这对于我的需求来说太复杂了。
作为起点,我的代码是这样工作的:
guard let depthData = frame.sceneDepth else { return }
let camera = frame.camera
let depthPixelBuffer = depthData.depthMap
let depthHeight = CVPixelBufferGetHeight(depthPixelBuffer)
let depthWidth = CVPixelBufferGetWidth(depthPixelBuffer)
let resizeScale = CGFloat(depthWidth) / CGFloat(CVPixelBufferGetWidth(frame.capturedImage))
let resizedColorImage = frame.capturedImage.toCGImage(scale: resizeScale);
guard let colorData = resizedColorImage.pixelData() else {
fatalError()
}
var intrinsics = camera.intrinsics;
let referenceDimensions = camera.imageResolution;
let ratio = Float(referenceDimensions.width) / Float(depthWidth)
intrinsics.columns.0[0] /= ratio
intrinsics.columns.1[1] /= ratio
intrinsics.columns.2[0] /= ratio
intrinsics.columns.2[1] /= ratio
var points: [SCNVector3] = []
let depthValues = depthPixelBuffer.depthValues()
for vv in 0..<depthHeight {
for uu in 0..<depthWidth {
let z = -depthValues[uu + vv * depthWidth]
let x = Float32(uu) / Float32(depthWidth) * 2.0 - 1.0;
let y = 1.0 - Float32(vv) / Float32(depthHeight) * 2.0;
points.append(SCNVector3(x,y,z))
}
}
生成的点云看起来不错,但在 Z 轴上严重弯曲。我意识到这段代码也没有针对屏幕方向进行调整。
解决方法
A Cupertino 在 developer.apple.com 的论坛上回复了我的回复:
无论是在 CPU 端还是 GPU 端,unprojection 计算本身都是相同的。
CPU 端,计算如下:
/// Returns a world space position given a point in the camera image,the eye space depth (sampled/read from the corresponding point in the depth image),the inverse camera intrinsics,and the inverse view matrix.
func worldPoint(cameraPoint: SIMD2<Float>,eyeDepth: Float,cameraIntrinsicsInversed: simd_float3x3,viewMatrixInversed: simd_float4x4) -> SIMD3<Float> {
let localPoint = cameraIntrinsicsInversed * simd_float3(cameraPoint,1) * -eyeDepth
let worldPoint = viewMatrixInversed * simd_float4(localPoint,1);
return (worldPoint / worldPoint.w)[SIMD3(0,1,2)];
}
已实现,看起来像
for vv in 0..<depthHeight {
for uu in 0..<depthWidth {
let z = -depthValues[uu + vv * depthWidth]
let viewMatInverted = (sceneView.session.currentFrame?.camera.viewMatrix(for: UIApplication.shared.statusBarOrientation))!.inverse
let worldPoint = worldPoint(cameraPoint: SIMD2(Float(uu),Float(vv)),eyeDepth: z,cameraIntrinsicsInversed: intrinsics.inverse,viewMatrixInversed: viewMatInverted * rotateToARCamera )
points.append(SCNVector3(worldPoint))
}
}
点云非常混乱,需要建立信心,并且在发生 Int 舍入的垂直方向上存在差距,但这是一个可靠的开始。缺少的功能来自上述问题中指向 Apple 演示项目的链接。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。