Ios 使用ARKit 2检测对象时显示边界框

Ios 使用ARKit 2检测对象时显示边界框,ios,swift,arkit,ios12,Ios,Swift,Arkit,Ios12,我扫描并训练了多个真实世界的对象。我有ARReferenceObject,应用程序可以很好地检测到它们 我面临的问题是,当一个对象没有明显的、充满活力的特征时,需要几秒钟才能返回检测结果,我可以理解。现在,我希望应用程序在试图检测对象时,在对象顶部显示一个边界框和一个活动指示器 我没有看到任何有关这方面的信息。此外,如果有任何方法可以获得检测开始的时间或被检测对象的置信度百分比 非常感谢您的帮助。在检测到ARReferenceObject之前,可以显示有关该对象的边界框;虽然我不知道你为什么要这

我扫描并训练了多个真实世界的对象。我有
ARReferenceObject
,应用程序可以很好地检测到它们

我面临的问题是,当一个对象没有明显的、充满活力的特征时,需要几秒钟才能返回检测结果,我可以理解。现在,我希望应用程序在试图检测对象时,在对象顶部显示一个边界框和一个活动指示器

我没有看到任何有关这方面的信息。此外,如果有任何方法可以获得检测开始的时间或被检测对象的置信度百分比


非常感谢您的帮助。

在检测到
ARReferenceObject
之前,可以显示有关该对象的
边界框
;虽然我不知道你为什么要这样做(无论如何,提前)

例如,假设您的referenceObject位于水平曲面上,您首先需要将估计的边界框放置在平面上(或使用其他方法提前放置),并且在检测ARPLANEACHOR和放置边界框时,很可能已经检测到您的模型

可能的方法:

毫无疑问,您知道,
ARReferenceObject
具有一个
中心
范围
比例
属性,以及一组与该对象关联的
rawFeaturePoints

因此,我们可以根据年Apple的一些示例代码创建我们自己的边界框节点,并创建我们自己的SCNNode,它将显示一个近似于
ARReferenceObject
大小的边界框,该边界框在被检测之前存储在本地

注意:您需要从Apple示例代码中找到“线框\ U着色器”,以便边界框渲染为透明:

import Foundation
import ARKit
import SceneKit

class BlackMirrorzBoundingBox: SCNNode {

    //-----------------------
    // MARK: - Initialization
    //-----------------------

    /// Creates A WireFrame Bounding Box From The Data Retrieved From The ARReferenceObject
    ///
    /// - Parameters:
    ///   - points: [float3]
    ///   - scale: CGFloat
    ///   - color: UIColor
    init(points: [float3], scale: CGFloat, color: UIColor = .cyan) {
        super.init()

        var localMin = float3(Float.greatestFiniteMagnitude)
        var localMax = float3(-Float.greatestFiniteMagnitude)

        for point in points {
            localMin = min(localMin, point)
            localMax = max(localMax, point)
        }

        self.simdPosition += (localMax + localMin) / 2
        let extent = localMax - localMin

        let wireFrame = SCNNode()
        let box = SCNBox(width: CGFloat(extent.x), height: CGFloat(extent.y), length: CGFloat(extent.z), chamferRadius: 0)
        box.firstMaterial?.diffuse.contents = color
        box.firstMaterial?.isDoubleSided = true
        wireFrame.geometry = box
        setupShaderOnGeometry(box)
        self.addChildNode(wireFrame)
    }

    required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) Has Not Been Implemented") }

    //----------------
    // MARK: - Shaders
    //----------------

    /// Sets A Shader To Render The Cube As A Wireframe
    ///
    /// - Parameter geometry: SCNBox
    func setupShaderOnGeometry(_ geometry: SCNBox) {
        guard let path = Bundle.main.path(forResource: "wireframe_shader", ofType: "metal", inDirectory: "art.scnassets"),
            let shader = try? String(contentsOfFile: path, encoding: .utf8) else {

                return
        }

        geometry.firstMaterial?.shaderModifiers = [.surface: shader]
    }

}
要显示边界框,您可以执行如下操作,注意在我的示例中,我有以下变量:

 @IBOutlet var augmentedRealityView: ARSCNView!
 let configuration = ARWorldTrackingConfiguration()
 let augmentedRealitySession = ARSession()
要在检测到实际对象本身之前显示边界框,可以在
viewDidLoad
中调用
func
loadBoundigBox
,例如:

/// Creates A Bounding Box From The Data Available From The ARObject In The Local Bundle
func loadBoundingBox(){

    //1. Run Our Session
    augmentedRealityView.session = augmentedRealitySession
    augmentedRealityView.delegate = self

    //2. Load A Single ARReferenceObject From The Main Bundle
    if let objectURL =  Bundle.main.url(forResource: "fox", withExtension: ".arobject"){

        do{
            var referenceObjects = [ARReferenceObject]()
            let object = try ARReferenceObject(archiveURL: objectURL)

            //3. Log it's Properties
            print("""
                Object Center = \(object.center)
                Object Extent = \(object.extent)
                Object Scale = \(object.scale)
                """)

            //4. Get It's Scale
            let scale = CGFloat(object.scale.x)

            //5. Create A Bounding Box
            let boundingBoxNode = BlackMirrorzBoundingBox(points: object.rawFeaturePoints.points, scale: scale)

            //6. Add It To The ARSCNView
            self.augmentedRealityView.scene.rootNode.addChildNode(boundingBoxNode)

            //7. Position It 0.5m Away From The Camera
            boundingBoxNode.position = SCNVector3(0, -0.5, -0.5)

            //8. Add It To The Configuration
            referenceObjects.append(object)
            configuration.detectionObjects = Set(referenceObjects)

        }catch{
            print(error)
        }

    }

    //9. Run The Session
    augmentedRealitySession.run(configuration, options: [.resetTracking, .removeExistingAnchors])
    augmentedRealityView.automaticallyUpdatesLighting = true
}
上面的示例简单地从未检测到的
ARReferenceObject
创建一个边界框,并将其放置在距离
相机0.5米的地方,产生如下结果:

当然,您首先需要处理边界框的位置,以及如何处理边界框“指示器”的移除

以下方法仅在检测到实际对象时显示边界框,例如:

//--------------------------
// MARK: - ARSCNViewDelegate
//--------------------------

extension ViewController: ARSCNViewDelegate{

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

        //1. Check We Have A Valid ARObject Anchor 
        guard let objectAnchor = anchor as? ARObjectAnchor else { return }

        //2. Create A Bounding Box Around Our Object
        let scale = CGFloat(objectAnchor.referenceObject.scale.x)
        let boundingBoxNode = BlackMirrorzBoundingBox(points: objectAnchor.referenceObject.rawFeaturePoints.points, scale: scale)
        node.addChildNode(boundingBoxNode)

    }

}
这会产生如下结果:

关于检测计时器,Apple示例代码中有一个示例,显示了检测模型所需的时间

以最粗糙的形式(不考虑毫秒),您可以这样做:

首先创建一个
定时器
和一个
var
来存储检测时间,例如:

var detectionTimer = Timer()

var detectionTime: Int = 0
//--------------------------
// MARK: - ARSCNViewDelegate
//--------------------------

extension ViewController: ARSCNViewDelegate{

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

        //1. Check We Have A Valid ARObject Anchor
        guard let _ = anchor as? ARObjectAnchor else { return }

        //2. Stop The Timer
        detectionTimer.invalidate()

        //3. Log The Detection Time
        print("Total Detection Time = \(detectionTime) Seconds")

        //4. Reset The Detection Time
        detectionTime = 0

    }

}
然后在运行
ARSessionConfiguration
时初始化计时器,例如:

/// Starts The Detection Timer
func startDetectionTimer(){

     detectionTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(logDetectionTime), userInfo: nil, repeats: true)
}

/// Increments The Total Detection Time Before The ARReference Object Is Detected
@objc func logDetectionTime(){
    detectionTime += 1

}
然后,当检测到
ARReferenceObject
时,使计时器失效并记录时间,例如:

var detectionTimer = Timer()

var detectionTime: Int = 0
//--------------------------
// MARK: - ARSCNViewDelegate
//--------------------------

extension ViewController: ARSCNViewDelegate{

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

        //1. Check We Have A Valid ARObject Anchor
        guard let _ = anchor as? ARObjectAnchor else { return }

        //2. Stop The Timer
        detectionTimer.invalidate()

        //3. Log The Detection Time
        print("Total Detection Time = \(detectionTime) Seconds")

        //4. Reset The Detection Time
        detectionTime = 0

    }

}
这应该足以让你开始


请注意,本例在扫描对象时没有提供边界框(请参阅Apple示例代码),它基于您的问题中暗示的现有ARReferenceObject提供了一个边界框(假设我解释正确)。

您可以共享任何源代码吗?请参阅:和。您是说扫描ARReference对象并显示边界框吗?或者在检测到现有ARReference对象之前显示其边界框?在检测到现有ARReference对象之前显示其边界框。请检查我的答案,因为这与您的问题相同。我已经更新了它,用额外的图片来澄清一切。这是IOS版的Swift,不是Unity:)…你好,Josh,谢谢你的回答。目前,我在检测对象时绘制边界框,而不是在检测到的对象上。我的答案的第一部分显示了一个边界框,该边界框来自您创建的arrefernce对象,而不是对象本身。边界框是根据arreference对象中保存的特征点创建的。如果您实际上是想在扫描对象时显示边界框,则可以使用Apple示例。虽然边界框是基于原始要素点绘制的