iOS revertir la proyección de la camera

Estoy tratando de estimar la position de mi dispositivo relacionada con un código QR en el espacio. Estoy usando ARKit y el framework Vision, ambos presentados en iOS 11, pero la respuesta a esta pregunta probablemente no dependa de ellos.

Con el marco Vision, puedo get el rectángulo que limita un código QR en el marco de la camera. Me gustaría hacer coincidir este rectángulo con la traducción del dispositivo y la rotation necesaria para transformar el código QR desde una position estándar.

Por ejemplo, si observo el marco:

* * B C A D * * 

mientras que si yo estuviera a 1 m del código QR, centrado en él, y suponiendo que el código QR tiene un lado de 10 cm, vería:

 * * A0 B0 D0 C0 * * 

¿Cuál ha sido la transformación de mi dispositivo entre esos dos fotogtwigs? Entiendo que un resultado exacto podría no ser posible, porque tal vez el código QR observado sea ligeramente no plano y estamos tratando de estimar una transformación afín en algo que no es uno perfectamente.

Supongo que el sceneView.pointOfView?.camera?.projectionTransform es más útil que el sceneView.pointOfView?.camera?.projectionTransform?.camera.projectionMatrix ya que el último ya tiene en count la transformación inferida del ARKit que no me interesa por este problema

¿Cómo lo haría?

 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 } 

==== Editar ====

Después de probar varias cosas, terminé yendo para la estimación de la position de la camera usando la proyección openCV y la resolución de la perspectiva, solvePnP Esto me da una rotation y traducción que debería representar la postura de la camera en el código QR referencel. Sin embargo, cuando se usan esos valores y se colocan objects correspondientes a la transformación inversa, donde el código QR debe estar en el espacio de la camera, obtengo valores desplazados imprecisos y no puedo hacer que la rotation funcione:

 // 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.captunetworkingImage), height: CVPixelBufferGetHeight(currentFrame.captunetworkingImage) ) 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 } 

Aquí está la salida:

introduzca la descripción de la imagen aquí

donde A, B, C, D son las esquinas del código QR en el order en que se pasan al progtwig.

El origen pnetworkingicho permanece en su lugar cuando el teléfono gira, pero se desplaza desde donde debería estar. Sorprendentemente, si cambio los valores de las observaciones, puedo corregir esto:

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

introduzca la descripción de la imagen aquí

y ahora el origen pnetworkingicho se mantiene firmemente en su lugar. Sin embargo, no entiendo de dónde provienen los valores de cambio.

Finalmente, intenté get una orientación fija en relación con el código QR referencel:

  var n = SCNNode(geometry: networkingGeometry) 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) 

La orientación está bien cuando miro el código QR directamente, pero luego cambia por algo que parece estar relacionado con la rotation del teléfono: introduzca la descripción de la imagen aquí

Las preguntas más sobresalientes que tengo son:

  • ¿Cómo resuelvo la rotation?
  • ¿De dónde provienen los valores de cambio de position?
  • ¿Qué relación simple hacen la rotation, la traducción, QRCornerCoordinatesInQRRef, observaciones, intrinsics verificar? ¿Es O ~ K ^ -1 * (R_3x2 | T) Q? Porque si es así eso está apagado por unos pocos order de magnitud.

Si eso es útil, aquí hay algunos valores numéricos:

 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 ====

He notado que la rotation funciona bien cuando el teléfono se mantiene horizontalmente paralelo al código QR (es decir, la matriz de rotation es [[a, 0, b], [0, 1, 0], [c, 0, d]] ), sin importar cuál sea la orientación real del código QR:

introduzca la descripción de la imagen aquí

Otra rotation no funciona.

Matemáticas (Trig.):

Ecuación

Notas: la parte inferior es l (la longitud del código QR), el ángulo izquierdo es k , y el ángulo superior es i (la camera)

Imagen