检查相机视图中是否不再显示ARReferenceImage

KNV*_*KNV 18 xcode scenekit swift arkit aranchor

我想检查相机视图中是否不再显示ARReferenceImage.目前我可以检查图像的节点是否在摄像机的视图中,但是当ARReferenceImage被另一个图像覆盖或者图像被移除时,该节点仍然可以在摄像机的视图中看到.

func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
    guard let node = self.currentImageNode else { return }

    if let pointOfView = sceneView.pointOfView {
        let isVisible = sceneView.isNode(node, insideFrustumOf: pointOfView)
        print("Is node visible: \(isVisible)")
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我需要检查图像是否不再可见,而不是图像的节点可见性.但我不知道这是否可行.第一个屏幕截图显示了找到下方图像时添加的三个框.当覆盖找到的图像时(见截图2)我想删除这些框.

找到带框的图像

带框的受控图像

KNV*_*KNV 13

我设法解决了这个问题!使用了一点MaybeI的代码和他的概念来解决问题,但以不同的方式.以下代码行仍用于重新激活图像识别.

// Delete anchor from the session to reactivate the image recognition
sceneView.session.remove(anchor: anchor) 
Run Code Online (Sandbox Code Playgroud)

让我解释.首先,我们需要添加一些变量.

// The scnNodeBarn variable will be the node to be added when the barn image is found. Add another scnNode when you have another image.    
var scnNodeBarn: SCNNode = SCNNode()
// This variable holds the currently added scnNode (in this case scnNodeBarn when the barn image is found)     
var currentNode: SCNNode? = nil
// This variable holds the UUID of the found Image Anchor that is used to add a scnNode    
var currentARImageAnchorIdentifier: UUID?
// This variable is used to call a function when there is no new anchor added for 0.6 seconds    
var timer: Timer!
Run Code Online (Sandbox Code Playgroud)

完整的代码,下面有评论.

/// - Tag: ARImageAnchor-Visualizing
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    guard let imageAnchor = anchor as? ARImageAnchor else { return }

    let referenceImage = imageAnchor.referenceImage

    // The following timer fires after 0.6 seconds, but everytime when there found an anchor the timer is stopped.
    // So when there is no ARImageAnchor found the timer will be completed and the current scene node will be deleted and the variable will set to nil
    DispatchQueue.main.async {
        if(self.timer != nil){
            self.timer.invalidate()
        }
        self.timer = Timer.scheduledTimer(timeInterval: 0.6 , target: self, selector: #selector(self.imageLost(_:)), userInfo: nil, repeats: false)
    }

    // Check if there is found a new image on the basis of the ARImageAnchorIdentifier, when found delete the current scene node and set the variable to nil
    if(self.currentARImageAnchorIdentifier != imageAnchor.identifier &&
        self.currentARImageAnchorIdentifier != nil
        && self.currentNode != nil){
            //found new image
            self.currentNode!.removeFromParentNode()
            self.currentNode = nil
    }

    updateQueue.async {

        //If currentNode is nil, there is currently no scene node
        if(self.currentNode == nil){

            switch referenceImage.name {
                case "barn":
                    self.scnNodeBarn.transform = node.transform
                    self.sceneView.scene.rootNode.addChildNode(self.scnNodeBarn)
                    self.currentNode = self.scnNodeBarn
                default: break
            }

        }

        self.currentARImageAnchorIdentifier = imageAnchor.identifier

        // Delete anchor from the session to reactivate the image recognition
        self.sceneView.session.remove(anchor: anchor)
    }

}
Run Code Online (Sandbox Code Playgroud)

在计时器完成时删除节点,表明没有找到新的ARImageAnchor.

@objc
    func imageLost(_ sender:Timer){
        self.currentNode!.removeFromParentNode()
        self.currentNode = nil
    }
Run Code Online (Sandbox Code Playgroud)

通过这种方式,当覆盖图像或找到新图像时,将删除当前添加的scnNode.

在此输入图像描述

遗憾的是,该解决方案无法解决图像的定位问题,原因如下:

ARKit不跟踪每个检测到的图像的位置或方向的变化.

  • 在ARKit 2.0中,我们可以选择跟踪图像,只需使用“ ARImageTrackingConfiguration”并将图像添加到“ trackingImages”变量中即可。 (2认同)

jls*_*ert 8

我认为目前不可能.

来自AR体验文档中识别图像:

设计您的AR体验,将检测到的图像用作虚拟内容的起点.

ARKit不跟踪每个检测到的图像的位置或方向的变化.如果您尝试将虚拟内容保留在检测到的图像上,则该内容可能无法正确保留.而是使用检测到的图像作为启动动态场景的参照系.


iOS 12.0的新答案

ARKit 2.0和iOS 12最终通过ARImageTrackingConfiguration或通过ARWorldTrackingConfiguration.detectionImages现在也跟踪图像位置的属性添加此功能.

Apple文档ARImageTrackingConfiguration列出了两种方法的优点:

使用ARImageTrackingConfiguration,ARKit不是通过跟踪设备相对于世界的运动来建立3D空间,而是仅通过检测和跟踪相机视图中已知2D图像的运动来建立3D空间.ARWorldTrackingConfiguration也可以检测图像,但每种配置都有自己的优势:

  • 与仅图像跟踪相比,世界跟踪具有更高的性能成本,因此您的会话可以使用ARImageTrackingConfiguration一次性可靠地跟踪更多图像.

  • 仅图像跟踪允许您仅在这些图像在摄像机视图中时才将虚拟内容锚定到已知图像.通过图像检测进行世界跟踪,您可以使用已知图像将虚拟内容添加到3D世界,并在图像不再可见时继续跟踪该内容在世界空间中的位置.

  • 世界跟踪在稳定,不动的环境中运行最佳.您可以使用仅图像跟踪在更多情况下将虚拟内容添加到已知图像 - 例如,移动地铁车厢内的广告.


Abr*_*res 6

检查ARKit当前是否跟踪的图像的正确方法是使用didUpdate节点上的ARImageAnchor中的“ isTracked”属性作为锚点功能。

为此,我使用下一个结构:

struct TrackedImage {
    var name : String
    var node : SCNNode?
}
Run Code Online (Sandbox Code Playgroud)

然后是带有所有图像名称的该结构的数组。

var trackedImages : [TrackedImage] = [ TrackedImage(name: "image_1", node: nil) ]
Run Code Online (Sandbox Code Playgroud)

然后在didAdd节点中进行锚定,将新内容设置为场景,并将该节点添加到trackedImages数组中的相应元素

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    // Check if the added anchor is a recognized ARImageAnchor
    if let imageAnchor = anchor as? ARImageAnchor{
        // Get the reference ar image
        let referenceImage = imageAnchor.referenceImage
        // Create a plane to match the detected image.
        let plane = SCNPlane(width: referenceImage.physicalSize.width, height: referenceImage.physicalSize.height)
        plane.firstMaterial?.diffuse.contents = UIColor(red: 1, green: 1, blue: 1, alpha: 0.5)
        // Create SCNNode from the plane
        let planeNode = SCNNode(geometry: plane)
        planeNode.eulerAngles.x = -.pi / 2
        // Add the plane to the scene.
        node.addChildNode(planeNode)
        // Add the node to the tracked images
        for (index, trackedImage) in trackedImages.enumerated(){
            if(trackedImage.name == referenceImage.name){
                trackedImage[index].node = planeNode
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,在didUpdate节点的锚函数中,我们在数组中搜索锚名称,并检查isTracked属性是否为false。

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    var trackedImages : [TrackedImage] = [ TrackedImage(name: "image_1", node: nil) ]
    if let imageAnchor = anchor as? ARImageAnchor{
        // Search the corresponding node for the ar image anchor
        for (index, trackedImage) in trackedImages.enumerated(){
            if(trackedImage.name == referenceImage.name){
                // Check if track is lost on ar image
                if(imageAnchor.isTracked){
                    // The image is being tracked
                    trackedImage.node?.isHidden = false // Show or add content
                }else{
                    // The image is lost
                    trackedImage.node?.isHidden = true // Hide or delete content
                }
                break
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当您想同时跟踪多个图像并知道何时丢失任何图像时,此解决方案有效。

注意:为了使此解决方案起作用,maximumNumberOfTrackedImages必须将AR配置中的设置为非零数字。


小智 5

不管它的价值如何,我花了几个小时试图找出如何不断检查图像引用。didUpdate 函数就是答案。然后您只需使用 .isTracked 属性测试参考图像是否被跟踪。此时,您可以将 .isHidden 属性设置为 true 或 false。这是我的例子:

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        let trackedNode = node

        if let imageAnchor = anchor as? ARImageAnchor{

        if (imageAnchor.isTracked) {
            trackedNode.isHidden = false
            print("\(trackedNode.name)")

        }else {
            trackedNode.isHidden = true

            //print("\(trackedImageName)")
            print("No image in view")

        }
        }
    }
Run Code Online (Sandbox Code Playgroud)