我正在从事机器人项目,并尝试获取跟踪对象的位置作为yTrack变量的值(请参见代码)。我可以从func handleVisionRequestUpdate打印yTrack,但是我需要在此功能之外访问yTrack才能与其他功能一起使用。以getCoord()为例。请帮忙!
import AVFoundation
import Vision
import UIKit
import Foundation
class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
var protocolString: String?
var inputStream: InputStream?
var outputStream: OutputStream?
var dataAsString: String?
var yTrack: Double?
@IBOutlet private weak var cameraView: UIView?
@IBOutlet private weak var highlightView: UIView? {
didSet {
self.highlightView?.layer.borderColor = UIColor.red.cgColor
self.highlightView?.layer.borderWidth = 4
self.highlightView?.backgroundColor = .clear
}
}
private let visionSequenceHandler = VNSequenceRequestHandler()
private lazy var cameraLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
private lazy var captureSession: AVCaptureSession = {
let session = AVCaptureSession()
session.sessionPreset = AVCaptureSession.Preset.photo
guard
let backCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back),
let input = try? AVCaptureDeviceInput(device: backCamera)
else { return session }
session.addInput(input)
return session
}()
override func viewDidLoad() {
super.viewDidLoad()
self.highlightView?.frame = .zero
self.cameraView?.layer.addSublayer(self.cameraLayer)
let videoOutput = AVCaptureVideoDataOutput()
videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "MyQueue"))
self.captureSession.addOutput(videoOutput)
self.captureSession.startRunning()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.cameraLayer.frame = self.cameraView?.bounds ?? .zero
}
public var lastObservation: VNDetectedObjectObservation?
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard
let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer),
let lastObservation = self.lastObservation
else { return }
let request = VNTrackObjectRequest(detectedObjectObservation: lastObservation, completionHandler: self.handleVisionRequestUpdate)
request.trackingLevel = .fast
do {
try self.visionSequenceHandler.perform([request], on: pixelBuffer)
} catch {
print("Throws: \(error)")
}
}
public func handleVisionRequestUpdate(_ request: VNRequest, error: Error?) {
test {(yTrack) in
DispatchQueue.main.async {
guard let newObservation = request.results?.first as? VNDetectedObjectObservation else { return }
self.lastObservation = newObservation
guard newObservation.confidence >= 0.3 else {
self.highlightView?.frame = .zero
return
}
self.transformedRect = newObservation.boundingBox
self.transformedRect!.origin.y = 1 - self.transformedRect!.origin.y
let convertedRect = self.cameraLayer.layerRectConverted(fromMetadataOutputRect: self.transformedRect!)
self.highlightView?.frame = convertedRect
}
}
let yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
// HERE IT WORKS, yTrack IS PRINTING, BUT I NEED IT OUTSIDE THIS FUNCTION
print(yTrack as Any)
}
public func test (returnCompletion: @escaping (AnyObject) -> () ){
DispatchQueue.global(qos: .background).async {
self.yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
returnCompletion(self.yTrack as AnyObject)
}
}
public func getCoord () {
//HERE IT DOESN'T WORK. NOTHING IS PRINTING FROM HERE.
print(yTrack)
}
答案 0 :(得分:0)
问题出在您的handleVisionRequestUpdate
函数上。
首先@Azat在注释中是正确的:声明let yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
时,将在此函数的范围内创建新变量,该变量与var yTrack
范围内的ViewController
没有任何关系。
因此,当您在此函数中打印yTrack
时,将打印函数的内部变量,该内部变量将在函数返回后销毁。为了能够在功能之外使用yTrack
,您需要为ViewController
的{{1}}分配新值,然后就可以在所需的任何功能中使用它了>
youTrack
第二个问题是yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
。在大多数情况下,将在此块之后执行该块中的代码
DispatchQueue.main.async
那是因为使用此块,您告诉编译器“为此代码块创建单独的«queue»,并在可能时异步执行”,因此在大多数情况下,此行let yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
print(yTrack as Any)
将完成在此行self.transformedRect = newObservation.boundingBox
之后,您将在此行中有上一个let yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
,如果我理解正确的话,您将在transformedRect
内。因此,请从此功能中删除nil
或将DispatchQueue.main.async
移入该功能。
答案 1 :(得分:0)
查看以下代码。我添加了很多评论,但没有进行测试。但是它应该解决问题。发生了一些令人困惑的事情。特别具有“测试”功能。另外,您可能想练习使用self.myVar或self.myFunc(),以便开始更好地了解哪些变量是局部变量,哪些是视图控制器上的属性:
public func handleVisionRequestUpdate(_ request: VNRequest, error: Error?) {
// test {(yTrack) in /// remove this since we removed it below
DispatchQueue.main.async {
guard let newObservation = request.results?.first as? VNDetectedObjectObservation else { return }
self.lastObservation = newObservation
guard newObservation.confidence >= 0.3 else {
self.highlightView?.frame = .zero
return
}
self.transformedRect = newObservation.boundingBox
self.transformedRect!.origin.y = 1 - self.transformedRect!.origin.y
let convertedRect = self.cameraLayer.layerRectConverted(fromMetadataOutputRect: self.transformedRect!)
self.highlightView?.frame = convertedRect
//
// Move these into the Dispatch closure
// let yTrack = Double(self.transformedRect?.origin.y ?? 0.5) // delete this one
yTrack = Double(self.transformedRect?.origin.y ?? 0.5) // replace it with this one
print(yTrack as Any)
}
}
//
// Remove this. I'm not sure what it does, but its making things more complex
//
// public func test (returnCompletion: @escaping (AnyObject) -> () ){
// DispatchQueue.global(qos: .background).async {
// self.yTrack = Double(self.transformedRect?.origin.y ?? 0.5)
// returnCompletion(self.yTrack as AnyObject)
// }
// }