Je vais essayer d'estimer mon appareil position par rapport à un QR code dans l'espace. Je suis en utilisant ARKit et la Vision du cadre, à la fois introduit dans iOS11, mais la réponse à cette question ne dépend pas d'eux.
Avec la Vision du cadre, je suis en mesure d'obtenir le rectangle qui délimite un QR code dans le cadre de l'appareil. J'aimerais correspondre à ce rectangle pour le dispositif de translation et de rotation nécessaire pour transformer le QR code à partir d'une position de référence.
Par exemple, si j'observe l'image:
* *
B
C
A
D
* *
alors que si j'étais à 1m de distance à partir du QR code, centré sur elle, et en supposant que le QR code a un côté de 10cm j'aimerais voir:
* *
A0 B0
D0 C0
* *
ce qui a été mon appareil de transformation entre ces deux images? Je comprends qu'un résultat exact pourrait ne pas être possible, parce que peut-être observés QR code est un peu hors du plan et nous essayons d'estimer une transformation affine sur quelque chose qui n'est pas parfaitement.
Je suppose que l' sceneView.pointOfView?.camera?.projectionTransform
est plus utile que l' sceneView.pointOfView?.camera?.projectionTransform?.camera.projectionMatrix
depuis le plus tard tient déjà compte de transformer déduit à partir de la ARKit que je ne suis pas intéressé à ce problème.
Comment pourrais-je le remplir
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
}
====Edit====
Après avoir essayé plusieurs choses, j'ai fini par aller pour la caméra pose d'estimation à l'aide d'openCV projection et le point de vue du solveur, solvePnP
Cela me donne de rotation et de translation, qui devrait représenter la caméra pose dans le QR code référentielle. Cependant lors de l'utilisation de ces valeurs et de placer des objets correspondant à la transformation inverse, où le QR code doit être dans la caméra de l'espace, je reçois inexactes valeurs décalées, et je ne suis pas en mesure d'obtenir la rotation de travailler:
// 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
}
Voici le résultat:
où A, B, C, D sont le QR code de coins dans l'ordre qu'ils sont passés au programme.
La prédiction de l'origine reste en place lorsque le téléphone tourne, mais il est déplacé de l'endroit où il devrait être. Étonnamment, si je déplace les observations des valeurs, je suis en mesure de corriger ce:
// (imageSize.height * (1 - $0.y), imageSize.width * $0.x)
// replaced by:
(imageSize.height * (1.35 - $0.y), imageSize.width * ($0.x - 0.2))
et maintenant, la prédiction de l'origine reste solidement en place. Cependant, je ne comprends pas d'où le changement des valeurs viennent.
Enfin, j'ai essayé d'obtenir une orientation fixe relativement au code QR référentielle:
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)
L'orientation est très bien, quand je regarde le code QR tout droit, mais alors il se déplace par quelque chose qui semble être liées au téléphone mobile en rotation:
Les questions en suspens que j'ai sont:
- Comment puis-je résoudre la rotation?
- où la position de décalage de valeurs proviennent de?
- Quelle relation simple n'rotation, translation, QRCornerCoordinatesInQRRef, des observations, des intrisics vérifier? Est-il O ~ K^-1 * (R_3x2 | T) Q ? Parce que si c'est pour finir par un peu d'ordre de grandeur.
Si c'est utile, voici quelques valeurs numériques:
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 ====
J'ai remarqué que la rotation fonctionne bien lorsque le téléphone reste à l'horizontale parallèle à la QR code (c'est à dire la matrice de rotation est [[a, 0, b], [0, 1, 0], [c, 0, d]]), sans que le QR code de l'orientation est:
De rotation ne fonctionne pas.