我是iOS新手,目前正在重构从VisionCoreML和ARKit教程获得的代码,该教程向检测到的对象添加了一个节点。
当前,如果i移动对象,则节点不会移动并跟踪该对象。我可以从苹果的在实时捕获中识别对象示例代码中看到,每当Vision在一个新的位置检测到对象时,他们就会使用图层并重新定位,这正是我希望用ARObject复制的。
有什么方法可以用ARKit实现这一点吗?
这方面的任何帮助都将不胜感激。谢谢。
编辑:使用解决方案的工作代码
@IBOutlet var sceneView: ARSCNView!
private var viewportSize: CGSize!
private var previousAnchor: ARAnchor?
private var trackingNode: SCNNode!
lazy var objectDetectionRequest: VNCoreMLRequest = {
do {
let model = try VNCoreMLModel(for: yolov5s(configuration: MLModelConfiguration()).model)
let request = VNCoreMLRequest(model: model) { [weak self] request, error in
self?.processDetections(for: request, error: error)
}
return request
} catch {
fatalError("Failed to load Vision ML model.")
}
}()
func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {
guard let capturedImage = sceneView.session.currentFrame?.capturedImage
else { return }
let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: capturedImage, orientation: .leftMirrored, options: [:])
do {
try imageRequestHandler.perform([objectDetectionRequest])
} catch {
print("Failed to perform image request.")
}
}
func processDetections(for request: VNRequest, error: Error?) {
guard error == nil else {
print("Object detection error: \(error!.localizedDescription)")
return
}
guard let results = request.results else { return }
for observation in results where observation is VNRecognizedObjectObservation {
let objectObservation = observation as! VNRecognizedObjectObservation
let topLabelObservation = objectObservation.labels.first
print(topLabelObservation!.identifier + " " + "\(Int(topLabelObservation!.confidence * 100))%")
guard recognisedObject(topLabelObservation!.identifier) && topLabelObservation!.confidence > 0.9
else { continue }
let rect = VNImageRectForNormalizedRect(
objectObservation.boundingBox,
Int(self.sceneView.bounds.width),
Int(self.sceneView.bounds.height))
let midPoint = CGPoint(x: rect.midX, y: rect.midY)
let raycastQuery = self.sceneView.raycastQuery(from: midPoint,
allowing: .estimatedPlane,
alignment: .any)
let raycastArray = self.sceneView.session.raycast(raycastQuery!)
guard let raycastResult = raycastArray.first else { return }
let position = SCNVector3(raycastResult.worldTransform.columns.3.x,
raycastResult.worldTransform.columns.3.y,
raycastResult.worldTransform.columns.3.z)
if let _ = trackingNode {
trackingNode!.worldPosition = position
} else {
trackingNode = createNode()
trackingNode!.worldPosition = position
self.sceneView.scene.rootNode.addChildNode(trackingNode!)
}
}
}
private func recognisedObject(_ identifier: String) -> Bool {
return identifier == "remote" || identifier == "mouse"
}
private func createNode() -> SCNNode {
let sphereNode = SCNNode(geometry: SCNSphere(radius: 0.01))
sphereNode.geometry?.firstMaterial?.diffuse.contents = UIColor.purple
return sphereNode
}
private func loadSession() {
let configuration = ARWorldTrackingConfiguration()
configuration.planeDetection = []
sceneView.session.run(configuration)
}
override func viewDidLoad() {
super.viewDidLoad()
sceneView.delegate = self
viewportSize = sceneView.frame.size
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadSession()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
sceneView.session.pause()
}发布于 2022-08-02 18:50:38
老实说,你在这里使用的技术不能开箱即用。YOLO (以及您换掉的任何其他对象检测模型)没有内置跟踪视频中相同对象的概念。它们在2D位图中查找对象,并为它们返回2D边界框。当相机或对象移动时,通过下一个capturedImage缓冲区,它将为您提供一个位于正确位置的新的边界框,但它无法知道是否是在前一个帧中检测到的对象的同一个实例。
要做到这一点,您需要对这些Vision结果进行一些后处理,以确定它是否是同一个对象,如果是的话,手动移动锚/网格以匹配新位置。如果您确信在任何时候只应该有一个对象在视图中,那么这是非常简单的。如果有多个对象,您将冒险进入复杂(但仍可实现)的领域。
您可以尝试合并视觉跟踪,但这可能会根据跟踪对象的性质和行为而起作用。
另外,sceneView.hitTest()也不受欢迎。您可能应该将其移植到使用ARSession.raycast()
https://stackoverflow.com/questions/73206186
复制相似问题