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.
drawCircle(... rotation)
) 2. Belum punya waktu untuk membaca spesifikasi 3. Sama seperti 2Jawaban:
Koordinasikan korespondensi sistem
Pertimbangkan bahwa
Vision
/CoreML
sistem koordinat tidak sesuai denganARKit
/SceneKit
sistem koordinat. Untuk detailnya lihat posting ini .Arah rotasi
Saya kira masalahnya bukan pada matriks. Ini dalam penempatan simpul. Untuk melacak gambar 2D Anda perlu menempatkan simpul ABCD berlawanan arah jarum jam (titik awalnya adalah simpul A yang terletak di asal imajiner
x:0, y:0
). Menurut saya, Dokumentasi Apple tentang kelas VNRectangleObservation (info tentang wilayah persegi panjang yang diproyeksikan terdeteksi oleh permintaan analisis gambar) tidak jelas. Anda menempatkan simpul Anda dalam urutan yang sama seperti di dokumentasi resmi:Tetapi mereka perlu ditempatkan dengan cara yang sama seperti arah rotasi positif (sekitar
Z
sumbu) terjadi pada sistem koordinat Cartesian:Ruang Koordinat Dunia di ARKit (serta di SceneKit dan Vision) selalu mengikuti a
right-handed convention
(Y
sumbu positif mengarah ke atas,Z
sumbu positif mengarah ke penampil, danX
sumbu positif mengarah ke kanan pengamat), tetapi diorientasikan berdasarkan konfigurasi sesi Anda . Kamera bekerja di Ruang Koordinat Lokal.Arah putaran pada sumbu apapun adalah positif (Berlawanan Arah Jarum Jam) dan negatif (Searah Jarum Jam). Untuk pelacakan di ARKit dan Vision, ini sangat penting.
Urutan rotasi juga masuk akal. ARKit, serta SceneKit, menerapkan rotasi relatif terhadap properti pivot node dalam urutan terbalik dari komponen: pertama
roll
(tentangZ
sumbu), laluyaw
(tentangY
sumbu), lalupitch
(tentangX
sumbu). Jadi urutan rotasinya adalahZYX
.sumber
Matematika (Trig.):
Catatan: bagian bawah adalah
l
(panjang kode QR), sudut kiri adalahk
, dan sudut atas adalahi
(kamera)sumber
i
dan jarak aslinyal
i
? Jika tidak sudut siku-sikul
maka ada lebih banyak matematika yang terlibat untuk menemukan salah satuk
atautheta
;i + k + theta = 180
.