на Nukepedia.

аюсь оценить положение моего устройства, связанного с QR-кодом в космосе. Я использую ARKit и Vision Framework, оба представленные в 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-кода:

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

Ответы на вопрос(2)

Ваш ответ на вопрос