首页 文章

iOS还原相机投影

提问于
浏览
86

我正在尝试估算与太空中QR码相关的设备位置 . 我正在使用ARKit和Vision框架,两者都在iOS11中引入,但这个问题的答案可能并不依赖于它们 .

使用Vision框架,我能够获得在相机框架中限制QR码的矩形 . 我想将此矩形与从标准位置转换QR码所需的设备平移和旋转相匹配 .

例如,如果我观察到框架:

*            *

    B
          C
  A
       D


*            *

如果我距离QR码1米远,以它为中心,假设QR码的边长为10cm,我会看到:

*            *


    A0  B0

    D0  C0


*            *

那两个帧之间的设备转换是什么?我知道确切的结果可能是不可能的,因为观察到的QR码可能是略微非平面的,我们试图估计一个不完美的东西上的仿射变换 .

我想 sceneView.pointOfView?.camera?.projectionTransformsceneView.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
}

这是输出:

enter image description here

其中A,B,C,D是它们传递给程序的顺序中的QR码角 .

当手机旋转时,预测的原点保持不变,但它会从应有的位置移动 . 令人惊讶的是,如果我移动观察值,我可以纠正这个:

// (imageSize.height * (1 - $0.y), imageSize.width * $0.x)
  // replaced by:
  (imageSize.height * (1.35 - $0.y), imageSize.width * ($0.x - 0.2))

enter image description here

现在预测的起源保持稳健 . 但是我不明白班次值的来源 .

最后,我试图获得相对于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)

当我直接查看二维码时,方向很好,但随后它会转移一些似乎与手机旋转有关的东西:
enter image description here

我遇到的突出问题是:

  • 如何解决旋转问题?

  • 位置偏移值来自哪里?

  • 什么简单的关系做旋转,翻译,QRCornerCoordinatesInQRRef,观察,内在验证?是O~K ^ -1 *(R_3x2 | T)Q?因为如果是这样的话会减少几个数量级 .

如果这有用,这里有一些数值:

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码时旋转工作正常(即旋转矩阵是[[a,0,b],[0,1,0],[c,0,d]] ),无论实际的QR码方向是什么:

enter image description here

其他旋转不起作用 .

2 回答

  • 1

    Math(Trig . ):

    Equation

    注意:底部是 l (QR码长度),左边角是 k ,顶角是 i (相机)

    Picture

  • 1

    我想这个问题不在矩阵中 . 它位于顶点位置 . 要跟踪2D图像,您需要逆时针放置ABCD顶点(起始点是位于 imaginary origin x:0, y:0 中的A顶点) . 我认为VNRectangleObservation上的Apple文档(关于图像分析请求检测到的投影矩形区域的信息)是模糊的 . 您按照官方文档中的顺序放置顶点:

    var bottomLeft: CGPoint
    var bottomRight: CGPoint
    var topLeft: CGPoint
    var topRight: CGPoint
    

    但它们需要以相同的方式放置,如在笛卡尔坐标系中发生正旋转方向(约 Z 轴):

    enter image description here

    ARKit中的世界坐标空间(以及SceneKit和Vision)始终跟随 right-handed convention (正 Y 轴指向上方,正 Z 轴指向观察者,正 X 轴指向观察者's right), but is oriented based on your session' s配置 . 相机工作于本地坐标空间 .

    任何轴的旋转方向为正(逆时针)和负(顺时针) . 对于ARKit和Vision中的跟踪,它至关重要 .

    enter image description here

    轮换顺序也很有意义 . ARKit和SceneKit以组件的相反顺序相对于节点的pivot属性应用旋转:首先 roll (约 Z 轴),然后 yaw (约 Y 轴),然后 pitch (约 X 轴) . 所以轮换顺序是 ZYX .

    此外,还有关于Nukepedia的Matrix Operations的有用帖子 .

相关问题