Я столкнулся с проблемой, которую не знаю, как решить.
Помещение
Мой проект происходит от этого .
Введение: объяснение проекта и целей
У меня есть белая листовая бумага А4, на которой я нарисовал схему с ручкой:
ПРИМЕЧАНИЕ: Знаки по бокам полезны для хорошего отслеживания изображения в режиме AR. Они просто дополнительные.
Цель состоит в том, чтобы отследить это изображение (как QRCode) и преобразовать нарисованную на нем схему в трехмерный объект, видимый в AR на изображении. Позже я хочу украсить сцену другими элементами, например, машиной для управления с помощью команд GUI и других 3D-объектов сцены.
Результат должен выглядеть примерно так:
Что я могу сделать до сих пор?
На самом деле отслеживание работает. Как вы можете видеть на видео , есть хорошее отслеживание. Чтобы достичь этого результата, я использую Vision для обнаружения прямоугольника . Таким образом, Vision обнаруживает изображение (прямоугольник), извлекает это изображение, добавляет некоторые фильтры и генерирует плоскость с новой текстурой + фильтры. Я использую ARImageTrackingConfiguration
для отслеживания извлеченного изображения. Я поместил над ним также космический корабль, например.
В чем моя проблема?
Мне нужно «извлечь» схему из изображения и добавить 3D-контент. Проблема в том, что я не знаю, как снова перейти с изображения, обнаруженного в Vision, на ARKit. У меня есть соответствие между исходным изображением (реальным изображением) и сгенерированной над ним плоскостью (которая имеет тот же размер и размеры). Но мне нужно такое же соответствие содержанию изображения.
Чтобы достичь цели извлечения, я играю с пикселями изображения.
Идея такова:
- Получите изображение, извлеченное с помощью Vision.
- Выберите несколько пикселей (точек) на извлеченном изображении (2D координаты).
- Получите относительные точки на плоскости (ARScene - 3D-координаты - Реальный мир).
- Используйте эти последние точки в качестве координат для создания 3D-формы (me sh).
Что я ищу?
Я не знаю, как получить все только что сказанные 4 шага. Я не понимаю, как получить точку на извлеченном изображении и получить ту же точку на плоскости в сцене .
ПРИМЕЧАНИЕ: это мой текущий подход, но если у кого-то есть идея получше, добро пожаловать.
Спасибо:)
Обновление
Я думаю, что есть 2 решения:
- Использование
hitTest
. Но я думаю, что это требует прикосновения к экрану (нажмите жест). Если это так, мне это не интересно. Пользователь будет вынужден прикоснуться пальцем ко всей дорожке, чтобы преобразовать трехмерный объект. - Извлечь изображение, проанализировать извлеченные пиксели изображения, преобразовать их в трехмерный объект, закрепить конечный объект на физической бумаге. отслеживается в 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)
}