iOS恢复相机投影
我正在尝试估算与空间QR码相关的设备位置。 我使用的是iOS11中引入的ARKit和Vision框架,但这个问题的答案可能不依赖于它们。
使用Vision框架,我可以获得在相机框架中绑定QR码的矩形。 我想匹配这个矩形的设备翻译和旋转所需的QR码从一个标准的位置转换。
例如,如果我观察框架:
* * B C A D * *
而如果我离QR码1m远,就以它为中心,假设QR码的边长为10cm,我会看到:
* * A0 B0 D0 C0 * *
这两个帧之间的设备转换是什么? 我知道一个确切的结果可能是不可能的,因为也许观察到的QR码是非平面的,我们试图估计一个不完全的东西的仿射变换。
我猜sceneView.pointOfView?.camera?.projectionTransform
比sceneView.pointOfView?.camera?.projectionTransform?.camera.projectionMatrix
更有帮助,因为后面已经考虑到了我不感兴趣的ARKit的变换对于这个问题。
我将如何填写
func get transform( qrCodeRectangle: VNBarcodeObservation, cameraTransform: SCNMatrix4) { // qrCodeRectangle.topLeft etc is the position in [0, 1] * [0, 1] of A0 // expected real world position of the QR code in a referential coordinate system let a0 = SCNVector3(x: -0.05, y: 0.05, z: 1) let b0 = SCNVector3(x: 0.05, y: 0.05, z: 1) let c0 = SCNVector3(x: 0.05, y: -0.05, z: 1) let d0 = SCNVector3(x: -0.05, y: -0.05, z: 1) let A0, B0, C0, D0 = ?? // CGPoints representing position in // camera frame for camera in 0, 0, 0 facing Z+ // then get transform from 0, 0, 0 to current position/rotation that sees // a0, b0, c0, d0 through the camera as qrCodeRectangle }
==== ====编辑
经过多次尝试之后,我最终使用openCV投影和透视求解器进行相机姿态估计, solvePnP
这给了我一个旋转和平移,它代表了QR码参考中的相机姿态。 但是,当使用这些值并放置与逆变换相对应的对象时,QR码应位于相机空间中,因此我得到不准确的偏移值,而我无法获得旋转的工作:
// some flavor of pseudo code below func renderer(_ sender: SCNSceneRenderer, updateAtTime time: TimeInterval) { guard let currentFrame = sceneView.session.currentFrame, let pov = sceneView.pointOfView else { return } let intrisics = currentFrame.camera.intrinsics let QRCornerCoordinatesInQRRef = [(-0.05, -0.05, 0), (0.05, -0.05, 0), (-0.05, 0.05, 0), (0.05, 0.05, 0)] // uses VNDetectBarcodesRequest to find a QR code and returns a bounding rectangle guard let qr = findQRCode(in: currentFrame) else { return } let imageSize = CGSize( width: CVPixelBufferGetWidth(currentFrame.capturedImage), height: CVPixelBufferGetHeight(currentFrame.capturedImage) ) let observations = [ qr.bottomLeft, qr.bottomRight, qr.topLeft, qr.topRight, ].map({ (imageSize.height * (1 - $0.y), imageSize.width * $0.x) }) // image and SceneKit coordinated are not the same // replacing this by: // (imageSize.height * (1.35 - $0.y), imageSize.width * ($0.x - 0.2)) // weirdly fixes an issue, see below let rotation, translation = openCV.solvePnP(QRCornerCoordinatesInQRRef, observations, intrisics) // calls openCV solvePnP and get the results let positionInCameraRef = -rotation.inverted * translation let node = SCNNode(geometry: someGeometry) pov.addChildNode(node) node.position = translation node.orientation = rotation.asQuaternion }
这是输出:
其中A,B,C,D是按照它们被传递给程序的顺序的QR码angular落。
当电话旋转时,预测的原点保持原位,但是它应该从原来的位置移开。 令人惊讶的是,如果我移动观察值,我可以纠正这一点:
// (imageSize.height * (1 - $0.y), imageSize.width * $0.x) // replaced by: (imageSize.height * (1.35 - $0.y), imageSize.width * ($0.x - 0.2))
现在预测的来源保持稳定。 但是我不明白这个转移值是从哪里来的。
最后,我试图find一个相对于QR码参考的定位:
var n = SCNNode(geometry: redGeometry) node.addChildNode(n) n.position = SCNVector3(0.1, 0, 0) n = SCNNode(geometry: blueGeometry) node.addChildNode(n) n.position = SCNVector3(0, 0.1, 0) n = SCNNode(geometry: greenGeometry) node.addChildNode(n) n.position = SCNVector3(0, 0, 0.1)
当我直接看QR码的时候,方向是好的,但是它随着一些似乎与电话轮换有关的事情而改变:
我拥有的杰出问题是:
- 我如何解决旋转?
- 位置偏移值从哪里来?
- 什么简单的关系做旋转,翻译,QRCornerCoordinatesInQRRef,观察,intrisicsvalidation? 是O〜K ^ -1 *(R_3x2 | T)Q? 因为如果是这样的话,closures几个数量级。
如果这有帮助,这里有一些数值:
Intrisics matrix Mat 3x3 1090.318, 0.000, 618.661 0.000, 1090.318, 359.616 0.000, 0.000, 1.000 imageSize 1280.0, 720.0 screenSize 414.0, 736.0
==== Edit2 ====
我注意到当手机与QR码保持水平平行时(即旋转matrix[[a,0,b],[0,1,0],[c,0,d]] ),不pipe实际的QR码方向是什么:
其他旋转不起作用。
math(Trig。):
注:底部是l
(QR码长度),左angular度是k
,顶部angular度是i
(相机)