ฉันกำลังพยายามประมาณตำแหน่งอุปกรณ์ของฉันที่เกี่ยวข้องกับโค้ด QR ในอวกาศ ฉันใช้ ARKit และ Vision framework ซึ่งทั้งคู่เปิดตัวใน iOS11 แต่คำตอบสำหรับคำถามนี้อาจไม่ได้ขึ้นอยู่กับคำถามเหล่านี้
ด้วยเฟรมเวิร์ก Vision ฉันสามารถรับสี่เหลี่ยมผืนผ้าที่ผูกโค้ด QR ในกรอบกล้องได้ ฉันต้องการจับคู่สี่เหลี่ยมผืนผ้านี้กับการแปลอุปกรณ์และการหมุนที่จำเป็นในการเปลี่ยนรหัส QR จากตำแหน่งมาตรฐาน
ตัวอย่างเช่นถ้าฉันสังเกตกรอบ:
* *
B
C
A
D
* *
ในขณะที่ฉันอยู่ห่างจากรหัส QR 1 เมตรโดยมีศูนย์กลางอยู่ที่มันและสมมติว่ารหัส QR มีด้าน 10 ซม. ฉันจะเห็น:
* *
A0 B0
D0 C0
* *
การเปลี่ยนแปลงอุปกรณ์ของฉันระหว่างสองเฟรมนั้นเป็นอย่างไร ฉันเข้าใจว่าผลลัพธ์ที่แน่นอนอาจเป็นไปไม่ได้เพราะบางทีโค้ด QR ที่สังเกตได้อาจไม่เป็นระนาบเล็กน้อยและเรากำลังพยายามประเมินการเปลี่ยนแปลงของสิ่งที่ไม่ใช่สิ่งที่สมบูรณ์แบบ
ฉันเดาว่าสิ่งsceneView.pointOfView?.camera?.projectionTransform
นี้มีประโยชน์มากกว่าsceneView.pointOfView?.camera?.projectionTransform?.camera.projectionMatrix
เนื่องจากในภายหลังได้คำนึงถึงการแปลงที่อนุมานจาก ARKit ที่ฉันไม่สนใจปัญหานี้
ฉันจะเติมอย่างไร
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
}
==== แก้ไข ====
หลังจากลองทำหลาย ๆ อย่างแล้วฉันก็เริ่มใช้การประมาณค่าท่าทางของกล้องโดยใช้การฉายภาพ openCV และตัวแก้มุมมองsolvePnP
สิ่งนี้ทำให้ฉันมีการหมุนและการแปลที่ควรเป็นตัวแทนของกล้องถ่ายรูปในการอ้างอิงรหัส QR อย่างไรก็ตามเมื่อใช้ค่าเหล่านั้นและวางวัตถุที่สอดคล้องกับการแปลงแบบผกผันโดยที่รหัส QR ควรอยู่ในพื้นที่กล้องฉันได้รับค่าที่เลื่อนไม่ถูกต้องและฉันไม่สามารถทำให้การหมุนทำงานได้:
// 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
}
นี่คือผลลัพธ์:
โดยที่ A, B, C, D คือมุมคิวอาร์โค้ดตามลำดับที่ส่งไปยังโปรแกรม
จุดเริ่มต้นที่คาดการณ์ไว้จะอยู่ในตำแหน่งเมื่อโทรศัพท์หมุน แต่จะเปลี่ยนไปจากที่ที่ควรจะเป็น น่าแปลกที่ถ้าฉันเปลี่ยนค่าการสังเกตฉันสามารถแก้ไขสิ่งนี้ได้:
// (imageSize.height * (1 - $0.y), imageSize.width * $0.x)
// replaced by:
(imageSize.height * (1.35 - $0.y), imageSize.width * ($0.x - 0.2))
และตอนนี้ต้นกำเนิดที่คาดการณ์ไว้ยังคงอยู่ในตำแหน่งที่ดี อย่างไรก็ตามฉันไม่เข้าใจว่าค่ากะมาจากไหน
ในที่สุดฉันได้พยายามกำหนดทิศทางให้คงที่สำหรับการอ้างอิงรหัส 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)
การวางแนวนั้นใช้ได้ดีเมื่อฉันมองไปที่รหัส QR ตรงๆ แต่มันก็เปลี่ยนไปตามสิ่งที่ดูเหมือนจะเกี่ยวข้องกับการหมุนโทรศัพท์:
คำถามที่ฉันมีคือ:
- ฉันจะแก้ปัญหาการหมุนได้อย่างไร?
- ค่ากะตำแหน่งมาจากไหน?
- ความสัมพันธ์ที่เรียบง่ายคืออะไรการหมุนการแปล QRCornerCoordinatesInQRRef การสังเกตการตรวจสอบ intrisics? มันคือ O ~ K ^ -1 * (R_3x2 | T) Q? เพราะถ้าเป็นอย่างนั้นมันก็จะออกตามลำดับความสำคัญไม่กี่ขนาด
หากเป็นประโยชน์นี่คือค่าตัวเลขบางส่วน:
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
==== แก้ไข 2 ====
ฉันสังเกตเห็นว่าการหมุนทำงานได้ดีเมื่อโทรศัพท์อยู่ในแนวนอนขนานกับโค้ด QR (เช่นเมทริกซ์การหมุนคือ [[a, 0, b], [0, 1, 0], [c, 0, d]] ) ไม่ว่าการวางแนวรหัส QR จริงจะเป็นอย่างไร:
การหมุนอื่น ๆ ไม่ทำงาน