اكتشف الوجوه باستخدام ML Kit على نظام iOS

يمكنك استخدام ML Kit لاكتشاف الوجوه في الصور والفيديو.

قبل ان تبدأ

  1. إذا لم تكن قد أضفت Firebase إلى تطبيقك بالفعل، فقم بذلك باتباع الخطوات الواردة في دليل البدء .
  2. قم بتضمين مكتبات ML Kit في ملف Podfile الخاص بك:
    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'
    
    بعد تثبيت أو تحديث Pods لمشروعك، تأكد من فتح مشروع Xcode الخاص بك باستخدام .xcworkspace .
  3. في تطبيقك، قم باستيراد Firebase:

    سويفت

    import Firebase

    ج موضوعية

    @import Firebase;

إرشادات إدخال الصورة

لكي تتمكن ML Kit من اكتشاف الوجوه بدقة، يجب أن تحتوي الصور المدخلة على وجوه يتم تمثيلها ببيانات بيكسل كافية. بشكل عام، يجب أن يكون حجم كل وجه تريد اكتشافه في الصورة 100 × 100 بكسل على الأقل. إذا كنت تريد اكتشاف ملامح الوجوه، فإن ML Kit يتطلب إدخالاً بدقة أعلى: يجب أن يكون كل وجه 200 × 200 بكسل على الأقل.

إذا كنت تكتشف وجوهًا في تطبيق في الوقت الفعلي، فقد ترغب أيضًا في مراعاة الأبعاد الإجمالية للصور المدخلة. يمكن معالجة الصور الأصغر حجمًا بشكل أسرع، وذلك لتقليل زمن الوصول، والتقاط الصور بدقة أقل (مع الأخذ في الاعتبار متطلبات الدقة المذكورة أعلاه) والتأكد من أن وجه الهدف يشغل أكبر قدر ممكن من الصورة. راجع أيضًا نصائح لتحسين الأداء في الوقت الفعلي .

قد يؤدي التركيز الضعيف للصورة إلى الإضرار بالدقة. إذا لم تحصل على نتائج مقبولة، فحاول مطالبة المستخدم باستعادة الصورة.

يمكن أن يؤثر أيضًا اتجاه الوجه بالنسبة للكاميرا على ميزات الوجه التي يكتشفها 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

ج موضوعية

// 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)
    

    ج موضوعية

    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)

      ج موضوعية

      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
          }
      }

      ج موضوعية

      - (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
      )

      ج موضوعية

      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

      ج موضوعية

      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
      // ...
    }
    

    ج موضوعية

    [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
  }
}

ج موضوعية

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 (ممكّن افتراضيًا).

  • فكر في التقاط الصور بدقة أقل. ومع ذلك، ضع في اعتبارك أيضًا متطلبات أبعاد الصورة لواجهة برمجة التطبيقات هذه.

  • خنق المكالمات إلى الكاشف. إذا أصبح إطار فيديو جديد متاحًا أثناء تشغيل الكاشف، قم بإسقاط الإطار.
  • إذا كنت تستخدم مخرجات الكاشف لتراكب الرسومات على الصورة المدخلة، فاحصل أولاً على النتيجة من ML Kit، ثم قم بعرض الصورة والتراكب في خطوة واحدة. من خلال القيام بذلك، يمكنك العرض على سطح العرض مرة واحدة فقط لكل إطار إدخال. راجع فئتي PreviewOverlayView و FIRDetectionOverlayView في نموذج تطبيق العرض للحصول على مثال.