Как преобразовать BoundingBox из VNRequest в CVPixelBuffer Coordinate - PullRequest
1 голос
/ 08 октября 2019

Я пытаюсь обрезать CVImageBuffer (из AVCaptureOutput), используя boundingBox обнаруженного лица из Vision (VNRequest). Когда я рисую над AVCaptureVideoPreviewLayer, используя:

let origin = previewLayer.layerPointConverted(fromCaptureDevicePoint: rect.origin)
let size = previewLayer.layerPointConverted(fromCaptureDevicePoint: rect.size.cgPoint)

для преобразования прямоугольника ограничивающего прямоугольника в координату previewLayer, все работает как положено. Но когда я пытаюсь применить к CVImageBuffer (с другим размером), результат неправильный.

enter image description here

Ниже вы можете увидеть, как я конвертируюкоордината возвращенного ограничивающего прямоугольника и способ обрезки CVPixelBuffer

class ViewController: UIViewController {
  var sequenceHandler = VNSequenceRequestHandler()

  func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
     // 1
     guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }

     // 2
     let detectFaceRequest = VNDetectFaceLandmarksRequest(completionHandler: { [weak self]  (request, error) in
       guard error == nil else { return }
       let cropedImage = self?.crop(request: request, imageBuffer: imageBuffer) // Croped buffer
     })

     // 3
     do {
       try sequenceHandler.perform(
         [detectFaceRequest],
         on: imageBuffer,
         orientation: .leftMirrored)
     } catch {
       print(error.localizedDescription)
     }
   }

  func crop(request: VNRequest, imageBuffer: CVImageBuffer) -> CVImageBuffer? {

     guard let results = request.results as? [VNFaceObservation], let result = results.first else { return nil }

     let width = CGFloat(CVPixelBufferGetWidth(imageBuffer)) // 1080
     let height = CGFloat(CVPixelBufferGetHeight(imageBuffer)) // 1920

     let cropRect = VNImageRectForNormalizedRect(result.boundingBox, Int(width), Int(height)) // Converting the boundingbox rect to the the image

     CVPixelBufferLockBaseAddress(imageBuffer, .readOnly)
     guard let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer) else { return nil }
     let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)

     let bytesPerPixel = 4
     let startAddress = baseAddress + Int(cropRect.origin.y) * bytesPerRow + Int(cropRect.origin.x) * bytesPerPixel

     guard let context = CGContext(data: startAddress, width: Int(cropRect.size.width), height: Int(cropRect.size.height), bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue), let data = context.data else {
       return nil
     }

     var pixelBuffer: CVPixelBuffer?
     let createBufferResult = CVPixelBufferCreateWithBytes(kCFAllocatorDefault, Int(cropRect.size.width), Int(cropRect.size.height), kCVPixelFormatType_32BGRA, data, bytesPerRow, nil, nil, nil, &pixelBuffer)

     guard createBufferResult != 0 else {
       print(createBufferResult)
       return nil
     }

     CVPixelBufferUnlockBaseAddress(imageBuffer, .readOnly)

     return pixelBuffer
   }
}
...