رصد الوجوه باستخدام حزمة تعلّم الآلة على نظام التشغيل iOS

يمكنك استخدام أدوات تعلّم الآلة لرصد الوجوه في الصور والفيديوهات.

تجربة السمات والبيانات

قبل البدء

  1. أدرِج مجموعات تعلّم الآلة التالية في Podfile:
    pod 'GoogleMLKit/FaceDetection', '3.2.0'
    
  2. بعد تثبيت أو تحديث مجموعات Pods لمشروعك، افتح مشروع Xcode باستخدام .xcworkspace. تتوفّر هذه الأداة في الإصدار 12.4 من Xcode أو إصدار أحدث.

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

بالنسبة إلى ميزة التعرّف على الوجه، يجب استخدام صورة بأبعاد لا تقل عن 480×360 بكسل. كي ترصد أدوات تعلُّم الآلة الوجوه بدقة، يجب أن تحتوي صور الإدخال على وجوه تمثّل بيانات بكسل كافية. وبشكل عام، يجب ألا يقل حجم كل وجه تريد رصده في الصورة عن 100x100 بكسل على الأقل. إذا كنت تريد اكتشاف محيط الوجوه، تتطلب أدوات تعلّم الآلة إدخال دقة أعلى: يجب أن يكون كل وجه 200x200 بكسل على الأقل.

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

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

يمكن أن يؤثّر اتجاه الوجه بالنسبة إلى الكاميرا أيضًا في ميزات الوجه التي ترصدها أدوات تعلّم الآلة. يمكنك الاطّلاع على مفاهيم التعرّف على الوجوه.

1- ضبط "أداة التعرّف على الوجوه"

قبل تطبيق ميزة "التعرّف على الوجه" على صورة، إذا أردت تغيير أي من الإعدادات التلقائية لأداة التعرّف على الوجوه، حدِّد هذه الإعدادات باستخدام عنصر FaceDetectorOptions. يمكنك تغيير الإعدادات التالية:

الإعدادات
performanceMode fast (الخيار التلقائي) | accurate

يمكنك تفضيل السرعة أو الدقة عند رصد الوجوه.

landmarkMode none (الخيار التلقائي) | all

لتحديد ما إذا كان يجب رصد "المعالم" للوجه، أي العيون أو الأذنين أو الأنف أو الخدين أو الفم - لكل الوجوه التي تم رصدها.

contourMode none (الخيار التلقائي) | all

تحديد ما إذا كان يجب تحديد أماكن ملامح الوجه. ويتم اكتشاف خطوط كونية للوجه الأكثر بروزًا فقط في الصورة.

classificationMode none (الخيار التلقائي) | all

لتحديد ما إذا كان سيتم تصنيف الوجوه إلى فئات، مثل "المبتسمة" و "العيون المفتوحة".

minFaceSize CGFloat (القيمة التلقائية: 0.1)

لضبط أصغر حجم مطلوب للوجه، ويتم التعبير عنه بنسبة عرض الرأس إلى عرض الصورة.

isTrackingEnabled false (الخيار التلقائي) | true

تحديد ما إذا كنت تريد تخصيص رقم تعريف للوجوه، والذي يمكن استخدامه لتتبُّع الوجوه عبر الصور.

وتجدر الإشارة إلى أنه عند تفعيل ميزة "رصد المحيط"، يتم اكتشاف وجه واحد فقط، لذلك لا تؤدي ميزة تتبُّع الوجه إلى نتائج مفيدة. لهذا السبب، ولتحسين سرعة الرصد، يجب عدم تفعيل ميزتَي "رصد خطوط المحيط" و"تتبّع الوجه".

على سبيل المثال، يمكنك إنشاء كائن FaceDetectorOptions مثل أحد الأمثلة التالية:

Swift

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

// Real-time contour detection of multiple faces
// options.contourMode = .all

Objective-C

// High-accuracy landmark detection and face classification
MLKFaceDetectorOptions *options = [[MLKFaceDetectorOptions alloc] init];
options.performanceMode = MLKFaceDetectorPerformanceModeAccurate;
options.landmarkMode = MLKFaceDetectorLandmarkModeAll;
options.classificationMode = MLKFaceDetectorClassificationModeAll;

// Real-time contour detection of multiple faces
// options.contourMode = MLKFaceDetectorContourModeAll;

2. تحضير صورة الإدخال

لاكتشاف الوجوه في صورة، عليك تمرير الصورة على أنّها UIImage أو CMSampleBufferRef إلى FaceDetector باستخدام إحدى الطريقتَين process(_:completion:) أو results(in:):

أنشِئ عنصر VisionImage باستخدام UIImage أو CMSampleBuffer.

في حال استخدام "UIImage"، يُرجى اتّباع الخطوات التالية:

  • يمكنك إنشاء عنصر VisionImage باستخدام UIImage. تأكَّد من تحديد سمة .orientation الصحيحة.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

في حال استخدام "CMSampleBuffer"، يُرجى اتّباع الخطوات التالية:

  • حدِّد اتجاه بيانات الصورة المضمّنة في CMSampleBuffer.

    للحصول على اتجاه الصورة:

    Swift

    func imageOrientation(
      deviceOrientation: UIDeviceOrientation,
      cameraPosition: AVCaptureDevice.Position
    ) -> UIImage.Orientation {
      switch deviceOrientation {
      case .portrait:
        return cameraPosition == .front ? .leftMirrored : .right
      case .landscapeLeft:
        return cameraPosition == .front ? .downMirrored : .up
      case .portraitUpsideDown:
        return cameraPosition == .front ? .rightMirrored : .left
      case .landscapeRight:
        return cameraPosition == .front ? .upMirrored : .down
      case .faceDown, .faceUp, .unknown:
        return .up
      }
    }
          

    Objective-C

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                                : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                                : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                                : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                                : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • ويمكنك إنشاء كائن VisionImage باستخدام كائن CMSampleBuffer واتجاهه:

    Swift

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    Objective-C

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

3. الحصول على مثيل من FaceDetector

الحصول على مثيل من FaceDetector:

Swift

let faceDetector = FaceDetector.faceDetector(options: options)

Objective-C

MLKFaceDetector *faceDetector = [MLKFaceDetector faceDetectorWithOptions:options];
      

4. معالجة الصورة

بعد ذلك، أدخِل الصورة إلى طريقة process():

Swift

weak var weakSelf = self
faceDetector.process(visionImage) { faces, error in
  guard let strongSelf = weakSelf else {
    print("Self is nil!")
    return
  }
  guard error == nil, let faces = faces, !faces.isEmpty else {
    // ...
    return
  }

  // Faces detected
  // ...
}

Objective-C

[faceDetector processImage:image
                completion:^(NSArray<MLKFace *> *faces,
                             NSError *error) {
  if (error != nil) {
    return;
  }
  if (faces.count > 0) {
    // Recognized faces
  }
}];

5. الحصول على معلومات حول الوجوه التي تم رصدها

إذا نجحت عملية التعرّف على الوجه، تمرِّر أداة رصد الوجه مصفوفة من كائنات Face إلى معالج الإكمال. يمثل كل عنصر Face وجهًا تم اكتشافه في الصورة. بالنسبة إلى كل وجه، يمكنك الحصول على إحداثيات حدوده في الصورة المدخلة، بالإضافة إلى أي معلومات أخرى أعددتها أداة اكتشاف الوجوه للعثور عليها. مثال:

Swift

for face in faces {
  let frame = face.frame
  if face.hasHeadEulerAngleX {
    let rotX = face.headEulerAngleX  // Head is rotated to the uptoward rotX degrees
  }
  if face.hasHeadEulerAngleY {
    let rotY = face.headEulerAngleY  // Head is rotated to the right rotY degrees
  }
  if face.hasHeadEulerAngleZ {
    let rotZ = face.headEulerAngleZ  // Head is tilted sideways 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
  }
}

Objective-C

for (MLKFace *face in faces) {
  // Boundaries of face in image
  CGRect frame = face.frame;
  if (face.hasHeadEulerAngleX) {
    CGFloat rotX = face.headEulerAngleX;  // Head is rotated to the upward rotX degrees
  }
  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):
  MLKFaceLandmark *leftEar = [face landmarkOfType:FIRFaceLandmarkTypeLeftEar];
  if (leftEar != nil) {
    MLKVisionPoint *leftEarPosition = leftEar.position;
  }

  // If contour detection was enabled:
  MLKFaceContour *upperLipBottomContour = [face contourOfType:FIRFaceContourTypeUpperLipBottom];
  if (upperLipBottomContour != nil) {
    NSArray<MLKVisionPoint *> *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" (مفعَّل تلقائيًا).

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

  • لمعالجة إطارات الفيديو، استخدِم واجهة برمجة التطبيقات المتزامنة results(in:) لأداة الرصد. ويمكنك استدعاء هذه الطريقة من وظيفة captureOutput(_, didOutput:from:) في AVCaptureVideoDataOutputSampleBufferDelegate للحصول على نتائج متزامنة من إطار الفيديو المحدّد. الاحتفاظ بـ AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames true لتقليل المكالمات الواردة إلى جهاز الرصد. في حال توفّر إطار فيديو جديد أثناء تشغيل أداة الرصد، سيتم تجاهله.
  • إذا كنت تستخدم نتيجة أداة الرصد لإضافة رسومات على الصورة التي تم إدخالها، احصل أولاً على النتيجة من أدوات تعلّم الآلة، ثم اعرض الصورة والتراكب في خطوة واحدة. بإجراء ذلك، يتم عرضك على سطح الشاشة مرة واحدة فقط لكل إطار إدخال تمت معالجته. للاطّلاع على مثال، يمكن الاطّلاع على updatePreviewOverlayViewWithLastFrame في نموذج البدء السريع في ML Kit.