Detección de Rostros con Cámara


¿Cómo puedo hacer la detección de rostros en tiempo real como lo hace la "cámara"?

introduzca la descripción de la imagen aquí

Me di cuenta de que AVCaptureStillImageOutput está en desuso después de 10.0, así que uso AVCapturePhotoOutput en su lugar. Sin embargo, encontré que la imagen que guardé para la detección facial no está tan satisfecha? Alguna idea?


UPDATE

Después de probar @Shravya Boggarapu mencionado. Actualmente, uso AVCaptureMetadataOutput para detectar la cara sin CIFaceDetector. Se funciona como se esperaba. Sin embargo, cuando estoy tratando de dibujar los límites de la cara, parece mal situado. Alguna idea?

introduzca la descripción de la imagen aquí

let metaDataOutput = AVCaptureMetadataOutput()

captureSession.sessionPreset = AVCaptureSessionPresetPhoto
    let backCamera = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .back)
    do {
        let input = try AVCaptureDeviceInput(device: backCamera)

        if (captureSession.canAddInput(input)) {
            captureSession.addInput(input)

            // MetadataOutput instead
            if(captureSession.canAddOutput(metaDataOutput)) {
                captureSession.addOutput(metaDataOutput)

                metaDataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
                metaDataOutput.metadataObjectTypes = [AVMetadataObjectTypeFace]

                previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
                previewLayer?.frame = cameraView.bounds
                previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill

                cameraView.layer.addSublayer(previewLayer!)
                captureSession.startRunning()
            }

        }

    } catch {
        print(error.localizedDescription)
    }

Y

extension CameraViewController: AVCaptureMetadataOutputObjectsDelegate {
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
    if findFaceControl {
        findFaceControl = false
        for metadataObject in metadataObjects {
            if (metadataObject as AnyObject).type == AVMetadataObjectTypeFace {
                print("
Author: Willjay, 2016-12-28

6 answers

Hay 2 formas de detectar caras: Una es CIFaceDetector y la otra es AVCaptureMetadataOutput

Dependiendo de sus necesidades, elija lo que sea relevante para usted.

CIFaceDetector tiene más características-Por ejemplo: Le da la ubicación de los ojos y la boca, detector de sonrisa, etc

Por otro lado, AVCaptureMetadataOutput se calcula en los fotogramas y las caras detectadas se rastrean y no hay código adicional necesario para ser añadido por nosotros. Me parece que debido a la las caras de seguimiento se detectan de forma más fiable en este proceso. La desventaja de esto es que simplemente detectará caras, sin posición de ojos/boca. Otra ventaja de este método es que los problemas de orientación son menores, ya que puede la videoOrientación cada vez que se cambia la orientación del dispositivo y la orientación de las caras será relativa a esa orientación

En mi caso, mi aplicación usa YUV420 como el formato requerido, por lo que usar CIDetector (que funciona con RGB) en tiempo real no fue viable. El uso de AVCaptureMetadataOutput ahorró mucho esfuerzo y realizó de manera más confiable debido al seguimiento continuo.

Una vez que tuve el cuadro delimitador para las caras, codifiqué características adicionales, como la detección de piel y lo apliqué en la imagen fija.

Nota: Al capturar imágenes fijas, la información de la caja de caras se agrega junto con los metadatos, por lo que no hay problemas de sincronización.

También puede utilizar una combinación de los dos para obtener mejores resultados.

Explorar y evalúe los pros y los contras según su aplicación.

UPDATE

El rectángulo de la cara es el origen de la imagen wrt. Así que para la pantalla, puede ser diferente. Utilice lo siguiente:

for (AVMetadataFaceObject *faceFeatures in metadataObjects) {
    CGRect face = faceFeatures.bounds;
    CGRect facePreviewBounds = CGRectMake(face.origin.y * previewLayerRect.size.width,
                               face.origin.x * previewLayerRect.size.height,
                               face.size.width * previewLayerRect.size.height,
                               face.size.height * previewLayerRect.size.width);

    /* Draw rectangle facePreviewBounds on screen */
}
 10
Author: Shravya Boggarapu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-06 13:21:51

Para realizar la detección de rostros en iOS, hay CIDetector (Apple) o Mobile Vision (Google) API.

IMO, Google Mobile Vision proporciona un mejor rendimiento.

Si estás interesado, aquí está el proyecto con el que puedes jugar. (iOS 10.2, Swift 3)


Después de WWDC 2017, Apple introduce CoreML en iOS 11. El marco Vision hace que la detección de rostros sea más precisa:)

He hecho una demostración Proyecto. contiene Vision v. s. CIDetector. Además, contiene detección de puntos de referencia de cara en tiempo real.

 6
Author: Willjay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-26 07:12:43
extension CameraViewController: AVCaptureMetadataOutputObjectsDelegate {
  func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
    if findFaceControl {
      findFaceControl = false
      let faces = metadata.flatMap { $0 as? AVMetadataFaceObject } .flatMap { (face) -> CGRect in
                  guard let localizedFace =
      previewLayer?.transformedMetadataObject(for: face) else { return nil }
                  return localizedFace.bounds }
      for face in faces {
        let temp = UIView(frame: face)
        temp.layer.borderColor = UIColor.white
        temp.layer.borderWidth = 2.0
        view.addSubview(view: temp)
      }
    }
  }
}

Asegúrese de eliminar las vistas creadas por didOutputMetadataObjects.

Mantener un registro de los identificadores faciales activos es la mejor manera de hacer esto ^

También cuando está tratando de encontrar la ubicación de las caras para su capa de vista previa, es mucho más fácil usar datos faciales y transformar. También creo que CIDetector es basura, metadataoutput utilizará cosas de hardware para la detección de rostros, lo que lo hace muy rápido.

 1
Author: jnblanchard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-18 01:19:49

Un poco tarde, pero aquí está la solución para el problema de las coordenadas. Hay un método que puede llamar a la capa de vista previa para transformar el objeto de metadatos en su sistema de coordenadas: transformedMetadataObject(para: metadataObject).

guard let transformedObject = previewLayer.transformedMetadataObject(for: metadataObject) else {
     continue
}
let bounds = transformedObject.bounds
showBounds(at: bounds)

Fuente: https://developer.apple.com/documentation/avfoundation/avcapturevideopreviewlayer/1623501-transformedmetadataobjectformeta

Por cierto, en caso de que esté utilizando (o actualice su proyecto a) Swift 4, el método delegado de AVCaptureMetadataOutputsObject ha cambiado a:

func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection)

Saludos cordiales

 1
Author: Elena,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-17 12:15:23

Al mirar su código, detecté 2 cosas que podrían conducir a una detección de rostros incorrecta/deficiente.

  1. Uno de ellos es el detector de caras con opciones donde se filtran los resultados por [CIDetectorSmile: true, CIDetectorEyeBlink: true]. Intenta configurarlo en cero: faceDetector?.features(in: faceImage, options: nil)
  2. Otra conjetura que tengo es el resultado orientación de la imagen. Me di cuenta de que utiliza el método AVCapturePhotoOutput.jpegPhotoDataRepresentation para generar la imagen de origen para la detección y el sistema, por defecto, genera esa imagen con un orientación, de tipo Left/LandscapeLeft, Creo. Por lo tanto, básicamente se puede decir que el detector de la cara para tener eso en mente mediante el uso de la CIDetectorImageOrientation llave.

CIDetectorImageOrientation : el valor de esta clave es un entero NSNumber de 1..8 como la que se encuentra en kCGImagePropertyOrientation. Si está presente, la detección se realizará en función de esa orientación, pero las coordenadas en las entidades devueltas seguirán basándose en las de la imagen.

Intenta configurarlo como faceDetector?.features(in: faceImage, options: [CIDetectorImageOrientation: 8 /*Left, bottom*/]).

 0
Author: ricardopereira,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-11 10:15:24
  1. Crear CaptureSession
  2. Para AVCaptureVideoDataOutput crear los siguientes ajustes

    Salida.videoSettings = [kCVPixelBufferPixelFormatTypeKey como AnyHashable: Int (kCMPixelFormat_32BGRA)]

3.Cuando reciba CMSampleBuffer, cree una imagen

DispatchQueue.main.async {
    let sampleImg = self.imageFromSampleBuffer(sampleBuffer: sampleBuffer)
    self.imageView.image = sampleImg
}
func imageFromSampleBuffer(sampleBuffer : CMSampleBuffer) -> UIImage
    {
        // Get a CMSampleBuffer's Core Video image buffer for the media data
        let  imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
        // Lock the base address of the pixel buffer
        CVPixelBufferLockBaseAddress(imageBuffer!, CVPixelBufferLockFlags.readOnly);


        // Get the number of bytes per row for the pixel buffer
        let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer!);

        // Get the number of bytes per row for the pixel buffer
        let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!);
        // Get the pixel buffer width and height
        let width = CVPixelBufferGetWidth(imageBuffer!);
        let height = CVPixelBufferGetHeight(imageBuffer!);

        // Create a device-dependent RGB color space
        let colorSpace = CGColorSpaceCreateDeviceRGB();

        // Create a bitmap graphics context with the sample buffer data
        var bitmapInfo: UInt32 = CGBitmapInfo.byteOrder32Little.rawValue
        bitmapInfo |= CGImageAlphaInfo.premultipliedFirst.rawValue & CGBitmapInfo.alphaInfoMask.rawValue
        //let bitmapInfo: UInt32 = CGBitmapInfo.alphaInfoMask.rawValue
        let context = CGContext.init(data: baseAddress, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo)
        // Create a Quartz image from the pixel data in the bitmap graphics context
        let quartzImage = context?.makeImage();
        // Unlock the pixel buffer
        CVPixelBufferUnlockBaseAddress(imageBuffer!, CVPixelBufferLockFlags.readOnly);

        // Create an image object from the Quartz image
        let image = UIImage.init(cgImage: quartzImage!);

        return (image);
    }
 0
Author: duzvik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-11 16:07:44