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-кода:

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

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

Guig
источник
Эй, вы пытаетесь определить расстояние между устройствами с помощью 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 есть полезный пост о матричных операциях .

Энди Федоров
источник