iOS ย้อนกลับการฉายภาพจากกล้อง


87

ฉันกำลังพยายามประมาณตำแหน่งอุปกรณ์ของฉันที่เกี่ยวข้องกับโค้ด 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 จริงจะเป็นอย่างไร:

ใส่คำอธิบายภาพที่นี่

การหมุนอื่น ๆ ไม่ทำงาน


เฮ้คุณกำลังพยายามหาระยะห่างของอุปกรณ์ผ่านรหัส QR หรือไม่? ถ้าเป็นเช่นนั้นดูคำตอบของฉันด้านล่าง
Ephellon Dantzler

แก้ไข: สำหรับคำถามค้างคาของคุณ 1. ดูเหมือนว่ามีการแทรกค่าที่ไม่จำเป็นเท่านั้น อาจเป็นไปได้ในวิธีการทำแผนที่ที่เรียกว่าหรือสิ่งอื่นใดที่เกี่ยวข้องกับวงกลมที่วาด (เช่นdrawCircle(... rotation)) 2. ไม่มีเวลาอ่านข้อกำหนด 3. เหมือนกับ 2
Ephellon Dantzler

คุณจะสามารถแบ่งปันรหัสบางส่วนได้หรือไม่?
Michal Zaborowski

คำตอบ:


2

การติดต่อของระบบพิกัด

พิจารณาว่าVision/ CoreMLระบบพิกัดไม่สอดคล้องกับARKit/ SceneKitระบบพิกัด สำหรับรายละเอียดดูที่โพสต์นี้

ทิศทางการหมุน

ฉันคิดว่าปัญหาไม่ได้อยู่ในเมทริกซ์ อยู่ในตำแหน่งจุดยอด สำหรับการติดตามภาพ 2 มิติคุณต้องวางจุดยอด ABCD ทวนเข็มนาฬิกา (จุดเริ่มต้นคือจุดยอด A ที่อยู่ในจุดกำเนิดจินตภาพ x:0, y:0 ) ฉันคิดว่าเอกสารของ Apple ในคลาสVNRectangleObservation (ข้อมูลเกี่ยวกับพื้นที่สี่เหลี่ยมที่คาดการณ์ไว้ซึ่งตรวจพบโดยคำขอวิเคราะห์รูปภาพ) นั้นคลุมเครือ คุณวางจุดยอดของคุณในลำดับเดียวกับในเอกสารอย่างเป็นทางการ:

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

แต่ต้องวางในลักษณะเดียวกันเช่นทิศทางการหมุนเชิงบวก (เกี่ยวกับZแกน) เกิดขึ้นในระบบพิกัดคาร์ทีเซียน:

ใส่คำอธิบายภาพที่นี่

World Coordinate Space ใน ARKit (เช่นเดียวกับใน SceneKit และ Vision) จะตามหลังเสมอright-handed convention( Yแกนบวกชี้ขึ้นZแกนบวกจะชี้ไปทางผู้ดูและXแกนบวกจะชี้ไปทางขวาของผู้ชม) แต่จะเน้นตามการกำหนดค่าเซสชันของคุณ . กล้องทำงานใน Local Coordinate Space

ทิศทางการหมุนของแกนใด ๆ เป็นค่าบวก (ทวนเข็มนาฬิกา) และลบ (ตามเข็มนาฬิกา) สำหรับการติดตามใน ARKit และ Vision มีความสำคัญอย่างยิ่ง

ใส่คำอธิบายภาพที่นี่

ลำดับการหมุนก็สมเหตุสมผลเช่นกัน ARKit เช่นเดียวกับ SceneKit ใช้การหมุนที่สัมพันธ์กับคุณสมบัติ Pivot ของโหนดในลำดับย้อนกลับของส่วนประกอบ: อันดับแรกroll(เกี่ยวกับZแกน) จากนั้นyaw(เกี่ยวกับYแกน) จากนั้นpitch(เกี่ยวกับXแกน) ZYXดังนั้นเพื่อหมุน


1

คณิตศาสตร์ (Trig.):

สมการ

หมายเหตุ: ด้านล่างคือl(ความยาวโค้ด QR) มุมซ้ายคือkและมุมบนคือi(กล้อง)

ภาพ


แน่นอน แต่ฉันรู้แค่มุมที่สังเกตได้iและระยะทางเดิมl
Guig

ไม่เป็นไรมีวิธีค้นหาสิ่งที่ตรงกันข้ามiหรือไม่? ถ้ามันไม่ใช่มุมฉากแสดงlว่ามีคณิตศาสตร์มากกว่าที่จะหาอย่างใดอย่างหนึ่งkหรือtheta; i + k + theta = 180.
Ephellon Dantzler

1
เพื่อให้ตรีโกณมิติทำงานได้ฉันต้องการระยะทางสองระยะและหนึ่งมุมหรือสองมุมและระยะทางเดียว ไม่มีทางที่จะได้ทุกอย่างจากมุมเดียวและระยะทางเดียว
Guig

ช่วยให้โค้ด QR เป็นสี่เหลี่ยมจัตุรัสเพื่อให้คุณสังเกตเห็นสองมุมทั้งแนวตั้งและแนวนอนได้หรือไม่?
Bob Wakefield
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.