6

我试图在我的 iOS 相机应用程序中检测人脸,但它不能正常工作,而它在 Camera.app 中工作正常。请注意:

  • 在我的应用程序中未检测到第一张脸,仅在 Camera.app 中。
  • 对于第三张脸——东亚女性——Camera.app 正确地在她的脸周围绘制了一个矩形,而我的应用程序绘制了一个延伸到她脸下方的矩形。
  • 在我的应用程序中没有检测到奥巴马的脸,只有在 Camera.app 中。
  • 当相机从普京的脸上缩小时,我的应用程序会在他的右半边脸上绘制一个矩形,将其切成两半,而 Camera.app 会在他的脸上正确地绘制一个矩形。

为什么会这样?

我的代码如下。你看有什么不对吗?

首先,我创建一个视频输出如下:

let videoOutput = AVCaptureVideoDataOutput()
videoOutput.videoSettings =
    [kCVPixelBufferPixelFormatTypeKey as AnyHashable: 
    Int(kCMPixelFormat_32BGRA)]

session.addOutput(videoOutput)

videoOutput.setSampleBufferDelegate(faceDetector, queue: faceDetectionQueue)

这是代表:

class FaceDetector: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate {
  func captureOutput(_ captureOutput: AVCaptureOutput!,
                     didOutputSampleBuffer sampleBuffer: CMSampleBuffer!,
                     from connection: AVCaptureConnection!) {
    let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
    let features = FaceDetector.ciDetector.features(
        in: CIImage(cvPixelBuffer: imageBuffer))

    let faces = features.map { $0.bounds }
    let imageSize = CVImageBufferGetDisplaySize(imageBuffer)

    let faceBounds = faces.map { (face: CIFeature) -> CGRect in
        var ciBounds = face.bounds

        ciBounds = ciBounds.applying(
            CGAffineTransform(scaleX: 1/imageSize.width, y: -1/imageSize.height))
        CGRect(x: 0, y: 0, width: 1, height: -1).verifyContains(ciBounds)

        let bounds = ciBounds.applying(CGAffineTransform(translationX: 0, y: 1.0))
        CGRect(x: 0, y: 0, width: 1, height: 1).verifyContains(bounds)
        return bounds
    }
    DispatchQueue.main.sync {
      facesUpdated(faceBounds, imageSize)
    }
  }

  private static let ciDetector = CIDetector(ofType: CIDetectorTypeFace,
      context: nil,
      options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])!
}

facesUpdated() 回调如下:

class PreviewView: UIView {
  private var faceRects = [UIView]()

  private static func makeFaceRect() -> UIView {
    let r = UIView()
    r.layer.borderWidth = FocusRect.borderWidth
    r.layer.borderColor = FocusRect.color.cgColor
    faceRects.append(r)
    addSubview(r)
    return r
  }

  private func removeAllFaceRects() {
    for faceRect in faceRects {
      verify(faceRect.superview == self)
      faceRect.removeFromSuperview()
    }
    faceRects.removeAll()
  }

  private func facesUpdated(_ faces: [CGRect], _ imageSize: CGSize) {
    removeAllFaceRects()

    let faceFrames = faces.map { (original: CGRect) -> CGRect in
        let face = original.applying(CGAffineTransform(scaleX: bounds.width, y: bounds.height))
        verify(self.bounds.contains(face))
        return face
    }

    for faceFrame in faceFrames {
      let faceRect = PreviewView.makeFaceRect()
      faceRect.frame = faceFrame
    }
  }
}

我也尝试了以下方法,但它们没有帮助:

  1. 将 AVCaptureVideoDataOutput 的 videoSettings 设置为 nil。
  2. 将 CIDetector 的方向显式设置为纵向。手机在此测试中是纵向的,所以没关系。
  3. 设置和删除 CIDetectorTracking: true
  4. 设置和删除 CIDetectorAccuracy:CIDetectorAccuracyHigh
  5. 通过仅查看检测到的第一个特征来尝试仅跟踪一张脸。
  6. 将 CVImageBufferGetDisplaySize() 替换为 CVImageBufferGetEncodedSize() - 它们无论如何都是相同的,在 1440 x 1080。
4

0 回答 0