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

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

ลองเลย

ก่อนเริ่มต้น

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

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

สำหรับการจดจำใบหน้า คุณควรใช้รูปภาพที่มีขนาดอย่างน้อย 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;
  }
}

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

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

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

ตัวอย่างตาข่ายคลุมหน้าที่ตรวจพบ

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

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

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

    การตรวจจับรูปร่าง
    การตรวจจับจุดสังเกต
    การจัดประเภท
    การตรวจหาและการแยกประเภทจุดสังเกต
    การตรวจจับเส้นโค้งและการตรวจจับจุดสังเกต
    การตรวจหาและการแยกประเภทรูปร่าง
    การตรวจจับเส้นโค้ง การตรวจหาจุดสังเกต และการแยกประเภท

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

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

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