iOS mengembalikan proyeksi kamera

87

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?.projectionTransformini lebih bermanfaat daripada sceneView.pointOfView?.camera?.projectionTransform?.camera.projectionMatrixkarena 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, solvePnPIni 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:

masukkan deskripsi gambar di sini

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

masukkan deskripsi gambar di sini

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:masukkan deskripsi gambar di sini

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:

masukkan deskripsi gambar di sini

Rotasi lain tidak berfungsi.

Guig
sumber
Hei, apakah Anda mencoba mendapatkan jarak perangkat melalui kode QR? Jika ya, lihat jawaban saya di bawah ini.
Ephellon Dantzler
EDIT: untuk pertanyaan luar biasa Anda, 1. Sepertinya ada nilai yang tidak perlu dimasukkan. Mungkin dalam metode pemetaan disebut, atau apa pun yang berhubungan dengan lingkaran yang digambar (seperti drawCircle(... rotation)) 2. Belum punya waktu untuk membaca spesifikasi 3. Sama seperti 2
Ephellon Dantzler
Apakah Anda dapat membagikan beberapa kode?
Michal Zaborowski

Jawaban:

2

Koordinasikan korespondensi sistem

Pertimbangkan bahwa Vision/ CoreMLsistem koordinat tidak sesuai dengan ARKit/ SceneKitsistem 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:

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

Tetapi mereka perlu ditempatkan dengan cara yang sama seperti arah rotasi positif (sekitar Zsumbu) terjadi pada sistem koordinat Cartesian:

masukkan deskripsi gambar di sini

Ruang Koordinat Dunia di ARKit (serta di SceneKit dan Vision) selalu mengikuti a right-handed convention( Ysumbu positif mengarah ke atas, Zsumbu positif mengarah ke penampil, dan Xsumbu 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.

masukkan deskripsi gambar di sini

Urutan rotasi juga masuk akal. ARKit, serta SceneKit, menerapkan rotasi relatif terhadap properti pivot node dalam urutan terbalik dari komponen: pertama roll(tentang Zsumbu), lalu yaw(tentang Ysumbu), lalu pitch(tentang Xsumbu). Jadi urutan rotasinya adalah ZYX.

Andy Fedoroff
sumber
1

Matematika (Trig.):

Persamaan

Catatan: bagian bawah adalah l(panjang kode QR), sudut kiri adalah k, dan sudut atas adalah i(kamera)

Gambar

Ephellon Dantzler
sumber
tentu, tapi saya hanya tahu sudut yang diamati idan jarak aslinyal
Guig
tidak apa-apa, adakah cara untuk menemukan kebalikan dari i? Jika tidak sudut siku-siku lmaka ada lebih banyak matematika yang terlibat untuk menemukan salah satu katau theta; i + k + theta = 180.
Ephellon Dantzler
1
Agar trigonometri bekerja, saya membutuhkan dua jarak dan satu sudut, atau dua sudut dan satu jarak. Tidak ada cara untuk mendapatkan semuanya hanya dari satu sudut dan satu jarak
Guig
Apakah membantu kode QR berbentuk persegi, sehingga Anda dapat mengamati dua sudut, baik vertikal maupun horizontal?
Bob Wakefield