Обнаружение лиц с помощью ML Kit на iOS

Вы можете использовать ML Kit для обнаружения лиц на изображениях и видео.

Прежде чем вы начнете

  1. Если вы еще не добавили Firebase в свое приложение, сделайте это, выполнив действия, описанные в руководстве по началу работы .
  2. Включите библиотеки ML Kit в свой подфайл:
    pod 'Firebase/MLVision', '6.25.0'
    # If you want to detect face contours (landmark detection and classification
    # don't require this additional model):
    pod 'Firebase/MLVisionFaceModel', '6.25.0'
    
    После установки или обновления модулей вашего проекта обязательно откройте проект Xcode, используя его .xcworkspace .
  3. Импортируйте Firebase в свое приложение:

    Быстрый

    import Firebase

    Цель-C

    @import Firebase;

Рекомендации по входному изображению

Чтобы ML Kit мог точно обнаруживать лица, входные изображения должны содержать лица, представленные достаточным количеством пиксельных данных. Как правило, каждое лицо, которое вы хотите обнаружить на изображении, должно иметь размер не менее 100x100 пикселей. Если вы хотите обнаружить контуры лиц, ML Kit требует ввода с более высоким разрешением: каждое лицо должно быть не менее 200x200 пикселей.

Если вы обнаруживаете лица в приложении реального времени, вам также может потребоваться учитывать общие размеры входных изображений. Изображения меньшего размера можно обрабатывать быстрее, поэтому для уменьшения задержки снимайте изображения с более низким разрешением (с учетом вышеуказанных требований к точности) и следите за тем, чтобы лицо объекта занимало как можно большую часть изображения. Также см. Советы по повышению производительности в реальном времени .

Плохая фокусировка изображения может снизить точность. Если вы не получили приемлемых результатов, попробуйте попросить пользователя повторно сделать снимок.

Ориентация лица относительно камеры также может влиять на то, какие черты лица распознает ML Kit. См. раздел «Концепции распознавания лиц» .

1. Настройте детектор лиц

Прежде чем применять распознавание лиц к изображению, если вы хотите изменить какие-либо настройки детектора лиц по умолчанию, укажите эти настройки с помощью объекта VisionFaceDetectorOptions . Вы можете изменить следующие настройки:

Настройки
performanceMode fast (по умолчанию) | accurate

Отдавайте предпочтение скорости и точности при обнаружении лиц.

landmarkMode none (по умолчанию) | all

Попытаться ли обнаружить лицевые «ориентиры» — глаза, уши, нос, щеки, рот — всех обнаруженных лиц.

contourMode none (по умолчанию) | all

Определять ли контуры черт лица. Контуры определяются только для наиболее заметного лица на изображении.

classificationMode none (по умолчанию) | all

Следует ли классифицировать лица по таким категориям, как «улыбка» и «открытые глаза».

minFaceSize CGFloat (по умолчанию: 0.1 )

Минимальный размер лиц для обнаружения относительно изображения.

isTrackingEnabled false (по умолчанию) | true

Следует ли назначать лицам идентификатор, который можно использовать для отслеживания лиц на изображениях.

Обратите внимание: когда включено распознавание контуров, распознается только одно лицо, поэтому отслеживание лиц не дает полезных результатов. По этой причине, а также для повышения скорости обнаружения не включайте одновременно распознавание контуров и отслеживание лица.

Например, создайте объект VisionFaceDetectorOptions , как показано в одном из следующих примеров:

Быстрый

// High-accuracy landmark detection and face classification
let options = VisionFaceDetectorOptions()
options.performanceMode = .accurate
options.landmarkMode = .all
options.classificationMode = .all

// Real-time contour detection of multiple faces
let options = VisionFaceDetectorOptions()
options.contourMode = .all

Цель-C

// High-accuracy landmark detection and face classification
FIRVisionFaceDetectorOptions *options = [[FIRVisionFaceDetectorOptions alloc] init];
options.performanceMode = FIRVisionFaceDetectorPerformanceModeAccurate;
options.landmarkMode = FIRVisionFaceDetectorLandmarkModeAll;
options.classificationMode = FIRVisionFaceDetectorClassificationModeAll;

// Real-time contour detection of multiple faces
FIRVisionFaceDetectorOptions *options = [[FIRVisionFaceDetectorOptions alloc] init];
options.contourMode = FIRVisionFaceDetectorContourModeAll;

2. Запустите детектор лиц

Чтобы обнаружить лица на изображении, передайте изображение как UIImage или CMSampleBufferRef в метод detect(in:) VisionFaceDetector :

  1. Получите экземпляр VisionFaceDetector :

    Быстрый

    lazy var vision = Vision.vision()
    
    let faceDetector = vision.faceDetector(options: options)
    

    Цель-C

    FIRVision *vision = [FIRVision vision];
    FIRVisionFaceDetector *faceDetector = [vision faceDetector];
    // Or, to change the default settings:
    // FIRVisionFaceDetector *faceDetector =
    //     [vision faceDetectorWithOptions:options];
    
  2. Создайте объект VisionImage , используя UIImage или CMSampleBufferRef .

    Чтобы использовать UIImage :

    1. При необходимости поверните изображение так, чтобы его свойство imageOrientation имело значение .up .
    2. Создайте объект VisionImage , используя правильно повернутый UIImage . Не указывайте метаданные вращения — необходимо использовать значение по умолчанию .topLeft .

      Быстрый

      let image = VisionImage(image: uiImage)

      Цель-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    Чтобы использовать CMSampleBufferRef :

    1. Создайте объект VisionImageMetadata , который задает ориентацию данных изображения, содержащихся в буфере CMSampleBufferRef .

      Чтобы получить ориентацию изображения:

      Быстрый

      func imageOrientation(
          deviceOrientation: UIDeviceOrientation,
          cameraPosition: AVCaptureDevice.Position
          ) -> VisionDetectorImageOrientation {
          switch deviceOrientation {
          case .portrait:
              return cameraPosition == .front ? .leftTop : .rightTop
          case .landscapeLeft:
              return cameraPosition == .front ? .bottomLeft : .topLeft
          case .portraitUpsideDown:
              return cameraPosition == .front ? .rightBottom : .leftBottom
          case .landscapeRight:
              return cameraPosition == .front ? .topRight : .bottomRight
          case .faceDown, .faceUp, .unknown:
              return .leftTop
          }
      }

      Цель-C

      - (FIRVisionDetectorImageOrientation)
          imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                                 cameraPosition:(AVCaptureDevicePosition)cameraPosition {
        switch (deviceOrientation) {
          case UIDeviceOrientationPortrait:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationLeftTop;
            } else {
              return FIRVisionDetectorImageOrientationRightTop;
            }
          case UIDeviceOrientationLandscapeLeft:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationBottomLeft;
            } else {
              return FIRVisionDetectorImageOrientationTopLeft;
            }
          case UIDeviceOrientationPortraitUpsideDown:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationRightBottom;
            } else {
              return FIRVisionDetectorImageOrientationLeftBottom;
            }
          case UIDeviceOrientationLandscapeRight:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationTopRight;
            } else {
              return FIRVisionDetectorImageOrientationBottomRight;
            }
          default:
            return FIRVisionDetectorImageOrientationTopLeft;
        }
      }

      Затем создайте объект метаданных:

      Быстрый

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )

      Цель-C

      FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
      AVCaptureDevicePosition cameraPosition =
          AVCaptureDevicePositionBack;  // Set to the capture device you used.
      metadata.orientation =
          [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                       cameraPosition:cameraPosition];
    2. Создайте объект VisionImage , используя объект CMSampleBufferRef и метаданные вращения:

      Быстрый

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      Цель-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Затем передайте изображение методу detect(in:) :

    Быстрый

    faceDetector.process(visionImage) { faces, error in
      guard error == nil, let faces = faces, !faces.isEmpty else {
        // ...
        return
      }
    
      // Faces detected
      // ...
    }
    

    Цель-C

    [faceDetector detectInImage:image
                     completion:^(NSArray<FIRVisionFace *> *faces,
                                  NSError *error) {
      if (error != nil) {
        return;
      } else if (faces != nil) {
        // Recognized faces
      }
    }];
    

3. Получить информацию об обнаруженных лицах

Если операция обнаружения лиц завершается успешно, детектор лиц передает массив объектов VisionFace обработчику завершения. Каждый объект VisionFace представляет лицо, обнаруженное на изображении. Для каждого лица вы можете получить его ограничивающие координаты во входном изображении, а также любую другую информацию, на поиск которой вы настроили детектор лиц. Например:

Быстрый

for face in faces {
  let frame = face.frame
  if face.hasHeadEulerAngleY {
    let rotY = face.headEulerAngleY  // Head is rotated to the right rotY degrees
  }
  if face.hasHeadEulerAngleZ {
    let rotZ = face.headEulerAngleZ  // Head is rotated upward rotZ degrees
  }

  // If landmark detection was enabled (mouth, ears, eyes, cheeks, and
  // nose available):
  if let leftEye = face.landmark(ofType: .leftEye) {
    let leftEyePosition = leftEye.position
  }

  // If contour detection was enabled:
  if let leftEyeContour = face.contour(ofType: .leftEye) {
    let leftEyePoints = leftEyeContour.points
  }
  if let upperLipBottomContour = face.contour(ofType: .upperLipBottom) {
    let upperLipBottomPoints = upperLipBottomContour.points
  }

  // If classification was enabled:
  if face.hasSmilingProbability {
    let smileProb = face.smilingProbability
  }
  if face.hasRightEyeOpenProbability {
    let rightEyeOpenProb = face.rightEyeOpenProbability
  }

  // If face tracking was enabled:
  if face.hasTrackingID {
    let trackingId = face.trackingID
  }
}

Цель-C

for (FIRVisionFace *face in faces) {
  // Boundaries of face in image
  CGRect frame = face.frame;

  if (face.hasHeadEulerAngleY) {
    CGFloat rotY = face.headEulerAngleY;  // Head is rotated to the right rotY degrees
  }
  if (face.hasHeadEulerAngleZ) {
    CGFloat rotZ = face.headEulerAngleZ;  // Head is tilted sideways rotZ degrees
  }

  // If landmark detection was enabled (mouth, ears, eyes, cheeks, and
  // nose available):
  FIRVisionFaceLandmark *leftEar = [face landmarkOfType:FIRFaceLandmarkTypeLeftEar];
  if (leftEar != nil) {
    FIRVisionPoint *leftEarPosition = leftEar.position;
  }

  // If contour detection was enabled:
  FIRVisionFaceContour *upperLipBottomContour = [face contourOfType:FIRFaceContourTypeUpperLipBottom];
  if (upperLipBottomContour != nil) {
    NSArray<FIRVisionPoint *> *upperLipBottomPoints = upperLipBottomContour.points;
    if (upperLipBottomPoints.count > 0) {
      NSLog("Detected the bottom contour of the subject's upper lip.")
    }
  }

  // If classification was enabled:
  if (face.hasSmilingProbability) {
    CGFloat smileProb = face.smilingProbability;
  }
  if (face.hasRightEyeOpenProbability) {
    CGFloat rightEyeOpenProb = face.rightEyeOpenProbability;
  }

  // If face tracking was enabled:
  if (face.hasTrackingID) {
    NSInteger trackingID = face.trackingID;
  }
}

Пример контуров лица

Если у вас включено распознавание контуров лица, вы получаете список точек для каждой обнаруженной черты лица. Эти точки представляют форму объекта. Подробную информацию о представлении контуров см. в разделе «Обзор концепций распознавания лиц ».

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

Обнаружение лиц в реальном времени

Если вы хотите использовать распознавание лиц в приложении реального времени, следуйте этим рекомендациям для достижения наилучшей частоты кадров:

  • Настройте детектор лиц для использования либо распознавания контура лица, либо классификации и обнаружения ориентиров, но не того и другого:

    Обнаружение контура
    Обнаружение ориентиров
    Классификация
    Обнаружение и классификация ориентиров
    Обнаружение контуров и обнаружение ориентиров
    Обнаружение и классификация контуров
    Обнаружение контуров, обнаружение ориентиров и классификация

  • Включить fast режим (включен по умолчанию).

  • Рассмотрите возможность захвата изображений с более низким разрешением. Однако также имейте в виду требования к размеру изображения этого API.

  • Дроссель вызывает детектор. Если новый видеокадр становится доступным во время работы детектора, удалите этот кадр.
  • Если вы используете выходные данные детектора для наложения графики на входное изображение, сначала получите результат из ML Kit, затем визуализируйте изображение и наложите его за один шаг. При этом вы выполняете рендеринг на поверхность дисплея только один раз для каждого входного кадра. Пример см. в классах PreviewOverlayView и FIRDetectionOverlayView в демонстрационном примере приложения.