Uzayda bir QR koduyla ilgili cihaz konumumu tahmin etmeye çalışıyorum. Her ikisi de iOS11'de sunulan ARKit ve Vision çerçevesini kullanıyorum, ancak bu sorunun cevabı muhtemelen onlara bağlı değil.
Vision çerçevesi ile kamera çerçevesindeki bir QR kodunu sınırlayan dikdörtgeni elde edebiliyorum. Bu dikdörtgeni, QR kodunu standart bir konumdan dönüştürmek için gereken cihaz çevirisiyle ve döndürmesiyle eşleştirmek istiyorum.
Örneğin, çerçeveyi gözlemlersem:
* *
B
C
A
D
* *
QR kodundan 1 m uzakta olsaydım, merkezde olsaydım ve QR kodunun 10 cm'lik bir kenarına sahip olduğunu varsayarsam şunu görürdüm:
* *
A0 B0
D0 C0
* *
bu iki çerçeve arasındaki cihaz dönüşümüm ne oldu? Kesin bir sonucun mümkün olmayabileceğini anlıyorum, çünkü gözlemlenen QR kodu biraz düzlemsel değildir ve mükemmel olmayan bir şey üzerinde afin bir dönüşümü tahmin etmeye çalışıyoruz.
Sanırım sceneView.pointOfView?.camera?.projectionTransform
, daha sceneView.pointOfView?.camera?.projectionTransform?.camera.projectionMatrix
sonra bu problem için ilgilenmediğim ARKit'ten çıkarılan dönüşümü hesaba kattığı için daha yararlıdır.
Nasıl doldururum
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
}
==== Düzenle ====
Bir çok şeyi denedikten sonra, openCV projeksiyonu ve perspektif çözücüyü kullanarak kamera poz tahminine gittim, solvePnP
Bu bana QR kod referansındaki kamera pozunu temsil etmesi gereken bir dönüş ve çeviri sağlıyor. Ancak bu değerleri kullanırken ve ters dönüşüme karşılık gelen nesneleri yerleştirirken, QR kodunun kamera alanında olması gerektiği yerde, yanlış kaydırılmış değerler alıyorum ve döndürmenin çalışmasını sağlayamıyorum:
// 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
}
İşte çıktı:
A, B, C, D, programa geçirildikleri sıraya göre QR kodu köşeleridir.
Tahmin edilen kaynak, telefon döndüğünde yerinde kalır, ancak olması gerektiği yerden kaydırılır. Şaşırtıcı bir şekilde, gözlem değerlerini değiştirirsem, bunu düzeltebilirim:
// (imageSize.height * (1 - $0.y), imageSize.width * $0.x)
// replaced by:
(imageSize.height * (1.35 - $0.y), imageSize.width * ($0.x - 0.2))
ve şimdi tahmin edilen kaynak sağlam bir şekilde yerinde kalıyor. Ancak vardiya değerlerinin nereden geldiğini anlamıyorum.
Son olarak, QR kod referansına göre sabitlenmiş bir yön bulmaya çalıştım:
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)
Doğrudan QR koduna baktığımda yönlendirme gayet iyi, ancak daha sonra telefonun dönüşüyle ilgili görünen bir şeyle değişiyor:
Sahip olduğum en önemli sorular:
- Dönüşü nasıl çözerim?
- konum kaydırma değerleri nereden geliyor?
- Rotasyon, çeviri, QRCornerCoordinatesInQRRef, gözlemler, intrisikler hangi basit ilişkiyi doğrular? O ~ K ^ -1 * (R_3x2 | T) Q mu? Çünkü eğer öyleyse, bu birkaç derece yanlıştır.
Yararlıysa, işte birkaç sayısal değer:
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
==== Düzenle2 ====
Telefon QR koduna yatay olarak paralel kaldığında döndürmenin iyi çalıştığını fark ettim (ör. Döndürme matrisi [[a, 0, b], [0, 1, 0], [c, 0, d]] ), gerçek QR kodu yönü ne olursa olsun:
Diğer rotasyon çalışmıyor.