Как перейти от координат изображения к ARKit World Coordinates? - PullRequest
2 голосов
/ 22 марта 2020

Я столкнулся с проблемой, которую не знаю, как решить.

Помещение

Мой проект происходит от этого .

Введение: объяснение проекта и целей

У меня есть белая листовая бумага А4, на которой я нарисовал схему с ручкой:

enter image description here

ПРИМЕЧАНИЕ: Знаки по бокам полезны для хорошего отслеживания изображения в режиме AR. Они просто дополнительные.

Цель состоит в том, чтобы отследить это изображение (как QRCode) и преобразовать нарисованную на нем схему в трехмерный объект, видимый в AR на изображении. Позже я хочу украсить сцену другими элементами, например, машиной для управления с помощью команд GUI и других 3D-объектов сцены.

Результат должен выглядеть примерно так:

enter image description here

Что я могу сделать до сих пор?

На самом деле отслеживание работает. Как вы можете видеть на видео , есть хорошее отслеживание. Чтобы достичь этого результата, я использую Vision для обнаружения прямоугольника . Таким образом, Vision обнаруживает изображение (прямоугольник), извлекает это изображение, добавляет некоторые фильтры и генерирует плоскость с новой текстурой + фильтры. Я использую ARImageTrackingConfiguration для отслеживания извлеченного изображения. Я поместил над ним также космический корабль, например.

В чем моя проблема?

Мне нужно «извлечь» схему из изображения и добавить 3D-контент. Проблема в том, что я не знаю, как снова перейти с изображения, обнаруженного в Vision, на ARKit. У меня есть соответствие между исходным изображением (реальным изображением) и сгенерированной над ним плоскостью (которая имеет тот же размер и размеры). Но мне нужно такое же соответствие содержанию изображения.

Чтобы достичь цели извлечения, я играю с пикселями изображения.

Идея такова:

  1. Получите изображение, извлеченное с помощью Vision.
  2. Выберите несколько пикселей (точек) на извлеченном изображении (2D координаты).
  3. Получите относительные точки на плоскости (ARScene - 3D-координаты - Реальный мир).
  4. Используйте эти последние точки в качестве координат для создания 3D-формы (me sh).

Что я ищу?

Я не знаю, как получить все только что сказанные 4 шага. Я не понимаю, как получить точку на извлеченном изображении и получить ту же точку на плоскости в сцене .

ПРИМЕЧАНИЕ: это мой текущий подход, но если у кого-то есть идея получше, добро пожаловать.

Спасибо:)


Обновление

Я думаю, что есть 2 решения:

  1. Использование hitTest. Но я думаю, что это требует прикосновения к экрану (нажмите жест). Если это так, мне это не интересно. Пользователь будет вынужден прикоснуться пальцем ко всей дорожке, чтобы преобразовать трехмерный объект.
  2. Извлечь изображение, проанализировать извлеченные пиксели изображения, преобразовать их в трехмерный объект, закрепить конечный объект на физической бумаге. отслеживается в ARKit.

Что вы думаете об этом?


Обновление

Лучшее изображение того, чего я хочу достичь: Изображение


Обновление

Ссылаясь на этот проект в качестве отправной точки, я использовал следующие шаги:

1. Обнаружение Rect angular фигур в пользовательской среде

Я использую Vision в режиме реального времени для проверки подачи камеры на наличие прямоугольников (10 раз в секунду).

// Every each second
init() {
    self.updateTimer = Timer.scheduledTimer(withTimeInterval: updateInterval, repeats: true) { [weak self] _ in
        if let capturedImage = ViewController.instance?.sceneView.session.currentFrame?.capturedImage {
            self?.search(in: capturedImage)
        }
    }
}

2. Обрезать канал камеры до наблюдаемого прямоугольника

Видение находит прямоугольники, я получаю первый, получаю координаты прямоугольника через VNRectangleObservation, применяю эти координаты к фильтру коррекции перспективы Core Image, чтобы обрезать его, оставляя только данные изображения внутри прямоугольной формы angular.

guard let rectangle = request?.results?.first as? VNRectangleObservation else {
    guard let error = error else { return }
    print("Error: Rectangle detection failed - Vision request returned an error. \(error.localizedDescription)")
    return
}
guard let filter = CIFilter(name: "CIPerspectiveCorrection") else {
    print("Error: Rectangle detection failed - Could not create perspective correction filter.")
    return
}
let width = CGFloat(CVPixelBufferGetWidth(currentCameraImage))
let height = CGFloat(CVPixelBufferGetHeight(currentCameraImage))
let topLeft = CGPoint(x: rectangle.topLeft.x * width, y: rectangle.topLeft.y * height)
let topRight = CGPoint(x: rectangle.topRight.x * width, y: rectangle.topRight.y * height)
let bottomLeft = CGPoint(x: rectangle.bottomLeft.x * width, y: rectangle.bottomLeft.y * height)
let bottomRight = CGPoint(x: rectangle.bottomRight.x * width, y: rectangle.bottomRight.y * height)

filter.setValue(CIVector(cgPoint: topLeft), forKey: "inputTopLeft")
filter.setValue(CIVector(cgPoint: topRight), forKey: "inputTopRight")
filter.setValue(CIVector(cgPoint: bottomLeft), forKey: "inputBottomLeft")
filter.setValue(CIVector(cgPoint: bottomRight), forKey: "inputBottomRight")

let ciImage = CIImage(cvPixelBuffer: currentCameraImage).oriented(.up)
filter.setValue(ciImage, forKey: kCIInputImageKey)

guard let perspectiveImage: CIImage = filter.value(forKey: kCIOutputImageKey) as? CIImage else {
    print("Error: Rectangle detection failed - perspective correction filter has no output image.")
    return
}
delegate?.rectangleFound(rectangleContent: perspectiveImage)

3. Создать эталонное изображение

Я создаю ARReferenceImage для отслеживания извлеченного изображения.

let possibleReferenceImage = ARReferenceImage(referenceImagePixelBuffer, orientation: .up, physicalWidth: CGFloat(0.5))

4. Отслеживание изображения с помощью ARKit

Я создаю сеанс отслеживания изображений и передаю эталонное изображение в свойство trackingImages конфигурации.

let configuration = ARImageTrackingConfiguration()
configuration.maximumNumberOfTrackedImages = 1
configuration.trackingImages = trackingImages
sceneView.session.run(configuration, options: runOptions)

Видение сделало первоначальное наблюдение о где изображение лежит в двухмерном пространстве в камере и позже ARKit разрешает свое местоположение в трехмерном пространстве, в физической среде.

Когда ARKit удается распознать изображение, он создает ARImageAnchor и узел SceneKit в правильном положении. Я сохраняю привязку и узел, которые дает вам ARKit, передавая их объекту AlteredImage.

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    alteredImage?.add(anchor, node: node)
    setMessageHidden(true)
}

5. Создание плоскости на изображении

Создание геометрии плоскости с такими же размерами извлеченного изображения.

init(_ size: CGSize) {
    print("[visualizationNode] Create a plane geometry")
    currentImage = createPlaneNode(size: size, rotation: -.pi / 2, contents: UIColor.clear)
    previousImage = createPlaneNode(size: size, rotation: -.pi / 2, contents: UIColor.clear)

    super.init()

    addChildNode(currentImage)
    addChildNode(previousImage)
}

6. Добавьте SCNPlane и космический корабль поверх него

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
    let node = SCNNode()

    // Add as plane node the first image detected
    let planeNode = SCNNode(geometry: 
    self.alteredImage?.visualizNode.childNodes.first!.geometry!)

    // Add ship to the scene
    // Get scene where is placed the ship
    guard let shipScene = SCNScene(named: "Modelss.scnassets/Ship/ship.scn")
    else { fatalError("Unable to load scene file.") }
    // Get ship node
    let shipNode = shipScene.rootNode.childNodes.first!
    // Set ship node position
    shipNode.position = planeNode.position
    // Set ship node scale
    shipNode.scale = SCNVector3(0.05, 0.05, 0.05)

    // Add ship as plane's child 
    planeNode.addChildNode(shipNode)

    // Add plane as node's child. The node will be the output
    node.addChildNode(planeNode)

    return node
}

7. Ответ на обновления отслеживания изображений

ARKit обновляет ARImageAnchor новым местоположением соответствующего изображения в физической среде и вызывает средство визуализации делегата (_: didUpdate: for :), чтобы уведомить приложение об изменении.

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    alteredImage?.update(anchor)
}

1 Ответ

0 голосов
/ 23 марта 2020

Этот ответ призван дать общее описание того, что, по моему мнению, могло бы быть сделано для решения вашей проблемы. К сожалению, я не смогу дать подробное описание с кодом, но я надеюсь, что это может помочь.

Первый подход

Используйте известное изображение на бумаге, установите это изображение, чтобы быть опорным изображением, и отслеживать это изображение с помощью ARKit.

По сути, вы нарисуете свои элементы, используя это изображение в качестве известной точки в пространстве. Для получения дополнительной информации см. Изображение ниже.

enter image description here

Отслеживая известное изображение, вы получите SCNNode , представляющий это изображение, и, если я не ошибаюсь, его локальная система координат находится в центре (как показано на рисунке). Вы можете добавить дочерние элементы к этому узлу, и они будут в системе координат известного изображения, то есть оси X, Y и Z будут такими же, как бумага формата A4.

В изображенной ситуации x_a > 0 и y_a <0, тогда как <em>x_b > 0 и y_b > 0, если положительная ось X идет вправо, а положительная ось Y идет вверх (вам нужно это подтвердить, потому что я не уверен).

Второй подход

Это больше похоже к тому, что вы хотите, но это сложнее. Вы должны использовать знаки, которые вы нарисовали в качестве ссылок. Вы можете отобразить карту из реальной системы координат в систему координат ARKit, выполнив тесты попаданий (см. документы ) в 3 известных точках, которые определяют плоскость.

Вам не нужно Пользователь должен коснуться экрана, чтобы выполнить проверку удара. Все, что вам нужно, это координаты в координатном пространстве нормализованного изображения. Этот шаг будет go после обработки вашего изображения. Я думаю, что это будет выглядеть так:

Обработка изображений

  1. Вы выполняете фильтры, необходимые для извлечения необходимой информации;
  2. В качестве дополнительного шага фильтр должен идентифицировать 3 известные точки, которые можно использовать для создания плоскости;
  3. Вы добавляете свои элементы относительно этой плоскости.

Проблема с этим подходить? Я думаю, что на ARKit нет простого способа сделать это, поэтому вам нужно реализовать большую часть логики c.

Заключительные слова

Переход с первым подходом намного проще, поэтому Я бы go с этим для первоначального прототипа. Возможно, позже вы могли бы перейти на более продвинутый подход.

Во всяком случае, я думаю, что самый сложный шаг - обработка изображений. Если вы сможете извлечь нужную информацию из бумаги, вы, вероятно, сможете использовать любой подход для рисования своих элементов.

...