Я пытаюсь использовать Vision и CoreML для передачи стилей отслеживаемых объектов как можно ближе к реальному времени. Я использую AVKit для захвата видео и AVCaptureVideoDataOutputSampleBufferDelegate для получения каждого кадра.
На высоком уровне мой пайплайн:
1) обнаруживать лица
2) обновите слои предварительного просмотра, чтобы рисовать ограничивающие рамки в нужном месте экрана.
3) обрезать исходное изображение до обнаруженных лиц
4) прогоняйте изображения лиц через модель coreML и получайте новые изображения в качестве вывода
5) заполните слои предварительного просмотра (где бы они ни находились) новыми изображениями
Я надеялся разместить ограничивающие прямоугольники, как только они будут вычислены (в основном потоке), а затем заполнить их, как только будет сделан вывод. Однако я обнаружил, что при добавлении вывода coreML в конвейер (в AVCaptureOutputQueue или CoreMLQueue) ограничивающие прямоугольники не обновляют позиции до завершения вывода. Возможно, мне что-то не хватает в том, как обрабатываются очереди при закрытии. Ниже приведены (надеюсь) соответствующие части кода.
Я изменяю код из https://developer.apple.com/documentation/vision/tracking_the_user_s_face_in_real_time.
public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer,
from connection: AVCaptureConnection) {
// omitting stuff that gets pixelBuffers etc formatted for use with Vision
// and sets up tracking requests
// Perform landmark detection on tracked faces
for trackingRequest in newTrackingRequests {
let faceLandmarksRequest = VNDetectFaceLandmarksRequest(completionHandler: { (request, error) in
guard let landmarksRequest = request as? VNDetectFaceLandmarksRequest,
let results = landmarksRequest.results as? [VNFaceObservation] else {
return
}
// Perform all UI updates (drawing) on the main queue,
//not the background queue on which this handler is being called.
DispatchQueue.main.async {
self.drawFaceObservations(results) //<<- places bounding box on the preview layer
}
CoreMLQueue.async{ //Queue for coreML uses
//get region of picture to crop for CoreML
let boundingBox = results[0].boundingBox
//crop the input frame to the detected object
let image: CVPixelBuffer = self.cropFrame(pixelBuffer: pixelBuffer, region: boundingBox)
//infer on region
let styleImage: CGImage = self.performCoreMLInference(on: image)
//on the main thread, place styleImage into the bounding box(CAShapeLayer)
DispatchQueue.main.async{
self.boundingBoxOverlayLayer?.contents = styleImage
}
}
})
do {
try requestHandler.perform(faceLandmarksRequest)
} catch let error as NSError {
NSLog("Failed Request: %@", error)
}
}
}
Помимо проблемы с очередью / синхронизацией, я думал, что одной из причин замедления может быть обрезка буфера пикселей до интересующей области. У меня здесь нет идей, любая помощь будет оценена