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-код, но затем он смещается на что-то, что, кажется, связано с поворотом телефона:введите описание изображения здесь

У меня есть нерешенные вопросы:

  • Как решить поворот?
  • откуда берутся значения сдвига позиции?
  • Какие простые отношения проверяют вращение, перевод, QRCornerCoordinatesInQRRef, наблюдения, интрисы? Это 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

==== Edit2 ====

Я заметил, что вращение работает нормально, когда телефон остается горизонтально параллельно QR-коду (т.е. матрица вращения [[a, 0, b], [0, 1, 0], [c, 0, d]] ), независимо от фактической ориентации QR-кода:

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

Другое вращение не работает.


Эй, вы пытаетесь определить расстояние между устройствами с помощью QR-кода? Если да, см. Мой ответ ниже.
— Ephellon Dantzler

РЕДАКТИРОВАТЬ: для ваших нерешенных вопросов: 1. Похоже, что просто вставлено ненужное значение. Возможно, в вызванном методе отображения или в чем-нибудь еще, имеющем отношение к нарисованным кругам (например, drawCircle(... rotation)) 2. Не было времени прочитать спецификации 3. То же, что и 2
— Эфеллон Данцлер

Сможете ли вы поделиться кодом?
— Michal Zaborowski

Ответы:


1

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

Уравнение

Примечания: внизу l(длина QR-кода), левый угол kи верхний угол i(камера)

Картина


Конечно, но я знаю только наблюдаемый угол iи исходное расстояниеl
— Guig

это нормально, есть ли способ найти противоположность i? Если это не прямой угол, lто потребуется больше математических вычислений, чтобы найти либо kили theta; i + k + theta = 180.
— Ephellon Dantzler

1
Чтобы тригонометрия работала, мне нужны либо два расстояния и один угол, либо два угла и одно расстояние. Там нет никакого способа , чтобы получить все , что только от одного угла и одной дистанции
— Guig

Помогает ли то, что QR-код имеет квадратную форму, чтобы вы могли наблюдать два угла: вертикальный и горизонтальный?
— Боб Уэйкфилд

1

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

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

Но их нужно размещать так же, как положительное направление вращения (вокруг Zоси) в декартовой системе координат:

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

Мировое координатное пространство в ARKit (а также в SceneKit и Vision) всегда следует за right-handed convention(положительная Yось направлена ​​вверх, положительная Zось указывает на зрителя, а положительная Xось указывает на зрителя вправо), но ориентирована на основе конфигурации вашего сеанса . Камера работает в локальном координатном пространстве.

Направление вращения вокруг любой оси положительное (против часовой стрелки) и отрицательное (по часовой стрелке). Для трекинга в ARKit и Vision это критически важно.

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

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

Кроме того, на Nukepedia есть полезный пост о матричных операциях .

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.