ตรวจจับใบหน้าด้วย ML Kit บน iOS

จัดทุกอย่างให้เป็นระเบียบอยู่เสมอด้วยคอลเล็กชัน บันทึกและจัดหมวดหมู่เนื้อหาตามค่ากำหนดของคุณ

คุณใช้ ML Kit เพื่อตรวจจับใบหน้าในรูปภาพและวิดีโอได้

ลองใช้งาน

  • ลองใช้แอปตัวอย่างเพื่อดูตัวอย่างการใช้งาน API นี้
  • ลองใช้โค้ดด้วยตนเองโดยใช้ codelab

ข้อควรทราบก่อนที่จะเริ่มต้น

  1. รวมพ็อด ML Kit ต่อไปนี้ใน Podfile
    pod 'GoogleMLKit/FaceDetection', '3.2.0'
    
  2. หลังจากติดตั้งหรืออัปเดตพ็อดของโปรเจ็กต์ ให้เปิดโปรเจ็กต์ Xcode โดยใช้ .xcworkspace XKit เวอร์ชัน 12.4 ขึ้นไปรองรับ ML Kit

หลักเกณฑ์เกี่ยวกับรูปภาพที่ป้อน

สําหรับการจดจําใบหน้า คุณควรใช้รูปภาพที่มีขนาดอย่างน้อย 480x360 พิกเซล เพื่อให้ ML Kit ตรวจจับใบหน้าได้อย่างถูกต้อง รูปภาพอินพุตต้องมีใบหน้าที่แสดงข้อมูลพิกเซลเพียงพอ โดยทั่วไป ใบหน้าแต่ละใบหน้าที่คุณต้องการตรวจจับในรูปภาพควรมีขนาดอย่างน้อย 100x100 พิกเซล หากต้องการตรวจจับการเกิดขึ้นของใบหน้า ML Kit ต้องใช้อินพุตที่มีความละเอียดสูงกว่า นั่นคือแต่ละใบหน้าควรมีขนาดอย่างน้อย 200x200 พิกเซล

หากตรวจพบใบหน้าในแอปพลิเคชันแบบเรียลไทม์ คุณอาจต้องพิจารณาขนาดโดยรวมของรูปภาพที่ป้อนด้วย รูปภาพขนาดเล็กอาจประมวลผลได้เร็วขึ้น ดังนั้นหากต้องการลดเวลาในการตอบสนอง ให้จับภาพที่ความละเอียดต่ําลง แต่อย่าลืมคํานึงถึงข้อกําหนดข้างต้นด้วย และตรวจดูว่าใบหน้าของวัตถุใช้รูปภาพให้มากที่สุดเท่าที่จะทําได้ และดูเคล็ดลับในการปรับปรุงประสิทธิภาพแบบเรียลไทม์

การโฟกัสรูปภาพที่ไม่ดีอาจส่งผลต่อความแม่นยําได้ หากไม่ได้รับผลการค้นหาที่ยอมรับได้ โปรดขอให้ผู้ใช้จับภาพอีกครั้ง

การวางแนวใบหน้าที่สัมพันธ์กับกล้องยังส่งผลต่อฟีเจอร์ใบหน้าซึ่ง ML Kit ตรวจจับได้ด้วย ดูแนวคิดการตรวจจับใบหน้า

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

ตัวอย่างโครงสร้างของใบหน้า

เมื่อเปิดใช้การตรวจจับการเกิดขึ้นของใบหน้า คุณจะได้รับรายการคะแนนสําหรับฟีเจอร์ใบหน้าแต่ละรายการที่ตรวจพบ จุดเหล่านี้แสดงถึงรูปร่างของฟีเจอร์ ดูแนวคิดการตรวจจับใบหน้าสําหรับรายละเอียดเกี่ยวกับวิธีแสดงแนวคิด

รูปภาพต่อไปนี้แสดงลักษณะที่จุดเหล่านี้แมปกับใบหน้า คลิกรูปภาพเพื่อขยาย

ตัวอย่าง Mesh Context Face Mesh

การตรวจจับใบหน้าแบบเรียลไทม์

หากต้องการใช้การตรวจจับใบหน้าในแอปพลิเคชันแบบเรียลไทม์ ให้ทําตามหลักเกณฑ์ต่อไปนี้เพื่อให้อัตราเฟรมดีที่สุด

  • กําหนดค่าตัวตรวจจับใบหน้าเพื่อใช้การตรวจจับใบหน้าหรือการแยกประเภทใบหน้าและการตรวจหาจุดสังเกต แต่ไม่ใช่ทั้ง 2 อย่าง

    การตรวจจับรอบทิศทาง
    การตรวจจับจุดสังเกต
    การแยกประเภทและการแยกประเภท
    การตรวจจับและการแยกประเภทจุดสังเกต
    การตรวจจับรอบทิศทางและการแยกประเภท
    การตรวจจับและการแยกประเภท
    การตรวจจับรอบทิศทาง การตรวจจับจุดสังเกต และการแยกประเภท

  • เปิดใช้โหมด fast (เปิดใช้โดยค่าเริ่มต้น)

  • ลองจับภาพที่ความละเอียดต่ําลง อย่างไรก็ตาม โปรดทราบว่า ข้อกําหนดด้านขนาดรูปภาพของ API นี้

  • สําหรับการประมวลผลเฟรมวิดีโอ ให้ใช้ results(in:) API แบบพร้อมกันของตัวตรวจจับ เรียกวิธีนี้จากฟังก์ชัน captureOutput(_, didOutput:from:) ของ AVCaptureVideoDataOutputSampleBufferDelegate เพื่อให้ได้ผลลัพธ์พร้อมกันจากเฟรมวิดีโอที่ระบุ เก็บ alwaysDiscardsLateVideoFrames ของ AVCaptureVideoDataOutput ไว้เป็น true เพื่อควบคุมการโทรไปยังตัวตรวจจับ หาก เฟรมวิดีโอใหม่พร้อมใช้งานระหว่างตัวตรวจจับจะทํางาน เฟรมจะหายไป
  • หากใช้เอาต์พุตของตัวตรวจจับเพื่อวางซ้อนกราฟิกบนรูปภาพอินพุต ก่อนอื่นให้ดูผลลัพธ์จาก ML Kit จากนั้นแสดงผลรูปภาพและวางซ้อนในขั้นตอนเดียว เมื่อทําเช่นนั้น คุณจะแสดงผลบนพื้นที่แสดงผลเพียงครั้งเดียวสําหรับเฟรมอินพุตแต่ละรายการที่ประมวลผลแล้ว ดูตัวอย่าง update PreviewOverlayViewWithLastFrame ในตัวอย่างคู่มือเริ่มใช้งานฉบับย่อสําหรับ ML Kit