iOS повернути проекцію камери


87

Я намагаюся оцінити положення свого пристрою, пов'язане з QR-кодом у просторі. Я використовую ARKit і структуру Vision, обидві представлені в iOS11, але відповідь на це питання, ймовірно, не залежить від них.

За допомогою рамки Vision я можу отримати прямокутник, який обмежує QR-код у кадрі камери. Я хотів би підібрати цей прямокутник до перекладу та обертання пристрою, необхідних для перетворення QR-коду зі стандартного положення.

Наприклад, якщо я спостерігаю кадр:

*            *

    B
          C
  A
       D


*            *

в той час, якби я знаходився на відстані 1 м від QR-коду, сконцентрований на ньому, і припускаючи, що 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 - кути QR-коду в тому порядку, в якому вони передаються програмі.

Прогнозоване джерело залишається на місці, коли телефон обертається, але воно зміщується з місця, де повинно бути. Дивно, але якщо я зміщую значення спостережень, я можу це виправити:

  // (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-код прямо, але потім він змінюється на щось, що, здається, пов’язано з обертанням телефону:введіть тут опис зображення

Вирішені запитання у мене:

  • Як вирішити обертання?
  • звідки беруться значення зсуву позиції?
  • Які прості відносини перевіряють обертання, переклад, QRCornerCoordinateInQRRef, спостереження, інтрики? Це 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
Ефеллон Дантцлер

Чи зможете ви поділитися яким-небудь кодом?
Міхал Заборовський

Відповіді:


1

Математика (триг.):

Рівняння

Примітки: нижній l(довжина QR-коду), лівий кут kі верхній кут i(камера)

Картина


звичайно, але я знаю лише спостережуваний кут iта початкову відстаньl
Гіг

це добре, чи є спосіб знайти протилежне i? Якщо це не прямий кут, lтоді є більше математики, щоб знайти kабо theta; i + k + theta = 180.
Ephellon Dantzler

1
Щоб тригонометрія працювала, мені потрібні або дві відстані і один кут, або два кути і одна відстань. Неможливо отримати все лише під одним кутом і на одній відстані
Гіг

Чи допомагає QR-код квадратним, щоб ви могли спостерігати два кути, як вертикальний, так і горизонтальний?
Боб Вейкфілд,

1

Я вважаю, що проблема не в матриці. Це в розміщенні вершин. Для відстеження 2D-зображень потрібно розмістити вершини ABCD проти годинникової стрілки (початкова точка - вершина, розташована в уявному початку x:0, y:0 ). Я думаю, що документація Apple щодо класу VNRectangleObservation (інформація про проектовані прямокутні області, виявлені за запитом на аналіз зображення) є неясною. Ви розмістили свої вершини в тому ж порядку, що і в офіційній документації:

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

Але їх потрібно розміщувати так само, як позитивний напрямок обертання (навколо Zосі) відбувається в декартовій системі координат:

введіть тут опис зображення

Світовий простір координат в ARKit (а також у SceneKit та Vision) завжди слідує за a right-handed convention (позитивна Yвісь спрямована вгору, позитивна Zвісь спрямована на глядача, а позитивна Xвісь спрямована праворуч від глядача), але орієнтована на основі конфігурації сеансу . Камера працює в локальному просторі координат.

Напрямок обертання навколо будь-якої осі є позитивним (проти годинникової стрілки) та негативним (за годинниковою стрілкою). Для відстеження в ARKit і Vision це критично важливо.

введіть тут опис зображення

Порядок обертання також має сенс. ARKit, як і SceneKit, застосовує обертання відносно властивості повороту вузла у зворотному порядку компонентів: спочатку roll(про Zвісь), потім yaw(про Yвісь), потім pitch(про Xвісь). Отже, порядок обертання є ZYX.

Крім того, є корисна публікація про Matrix Operations на Nukepedia.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.