Saya mencoba memperkirakan posisi perangkat saya terkait dengan kode QR di luar angkasa. Saya menggunakan ARKit dan kerangka kerja Vision, keduanya diperkenalkan di iOS11, tetapi jawaban atas pertanyaan ini mungkin tidak bergantung pada mereka.
Dengan kerangka kerja Vision, saya bisa mendapatkan persegi panjang yang membatasi kode QR di bingkai kamera. Saya ingin mencocokkan persegi panjang ini dengan terjemahan dan rotasi perangkat yang diperlukan untuk mengubah kode QR dari posisi standar.
Misalnya jika saya mengamati bingkai:
* *
B
C
A
D
* *
sedangkan jika saya berada 1 m dari kode QR, berpusat di atasnya, dan menganggap kode QR memiliki sisi 10cm, saya akan melihat:
* *
A0 B0
D0 C0
* *
apa yang telah menjadi transformasi perangkat saya antara dua bingkai itu? Saya memahami bahwa hasil yang tepat mungkin tidak dapat dilakukan, karena mungkin kode QR yang diamati sedikit non-planar dan kami mencoba memperkirakan transformasi affine pada sesuatu yang tidak sempurna.
Saya kira sceneView.pointOfView?.camera?.projectionTransform
ini lebih bermanfaat daripada sceneView.pointOfView?.camera?.projectionTransform?.camera.projectionMatrix
karena nanti sudah memperhitungkan transformasi yang disimpulkan dari ARKit yang saya tidak tertarik untuk masalah ini.
Bagaimana saya mengisi
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 ====
Setelah mencoba beberapa hal, saya akhirnya melakukan estimasi pose kamera menggunakan proyeksi openCV dan pemecah perspektif, solvePnP
Ini memberi saya rotasi dan terjemahan yang harus mewakili pose kamera dalam referensi kode QR. Namun ketika menggunakan nilai-nilai itu dan menempatkan objek yang sesuai dengan transformasi terbalik, di mana kode QR harus berada di ruang kamera, saya mendapatkan nilai pergeseran yang tidak akurat, dan saya tidak bisa mendapatkan rotasi untuk bekerja:
// 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
}
Inilah hasilnya:
di mana A, B, C, D adalah sudut kode QR sesuai urutan diteruskan ke program.
Asal yang diprediksi tetap di tempatnya saat telepon berputar, tetapi bergeser dari tempat seharusnya. Anehnya, jika saya menggeser nilai observasi, saya bisa mengoreksi ini:
// (imageSize.height * (1 - $0.y), imageSize.width * $0.x)
// replaced by:
(imageSize.height * (1.35 - $0.y), imageSize.width * ($0.x - 0.2))
dan sekarang asal prediksi tetap kuat di tempatnya. Namun saya tidak mengerti darimana nilai pergeseran itu berasal.
Akhirnya, saya mencoba untuk mendapatkan orientasi yang relatif tetap ke referensi kode 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)
Orientasinya baik-baik saja ketika saya melihat langsung kode QR, tetapi kemudian bergeser oleh sesuatu yang tampaknya terkait dengan rotasi telepon:
Pertanyaan penting yang saya miliki adalah:
- Bagaimana cara mengatasi rotasi?
- dari mana asal nilai pergeseran posisi?
- Hubungan sederhana apa yang dilakukan rotasi, terjemahan, QRCornerCoordinatesInQRRef, observasi, intrisik? Apakah O ~ K ^ -1 * (R_3x2 | T) Q? Karena jika demikian, itu meleset beberapa urutan besarnya.
Jika itu membantu, berikut adalah beberapa nilai numerik:
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 ====
Saya perhatikan bahwa rotasi berfungsi dengan baik ketika ponsel tetap horizontal sejajar dengan kode QR (yaitu matriks rotasi [[a, 0, b], [0, 1, 0], [c, 0, d]] ), apa pun orientasi kode QR yang sebenarnya:
Rotasi lain tidak berfungsi.