你可以使用 ML Kit 偵測圖片和影片中的臉孔。
立即體驗
事前準備
- 在 Podfile 中加入下列 ML Kit pod:
pod 'GoogleMLKit/FaceDetection', '3.2.0'
- 安裝或更新專案的 Pod 後,請使用其
.xcworkspace
開啟 Xcode 專案。Xcode 12.4 以上版本支援 ML Kit。
輸入圖片使用規範
如要進行臉部辨識,請使用尺寸至少為 480x360 像素的圖片。為了讓 ML Kit 準確偵測臉孔,輸入圖片必須包含以足夠像素資料表示的臉孔。一般來說,要在圖片中偵測的每個臉孔都至少應為 100x100 像素。如要偵測臉部的輪廓,使用 ML Kit 時需要更高的解析度:每個臉孔至少要有 200 x 200 像素。
如果您在即時應用程式中偵測到臉孔,可能也會考慮輸入圖片的整體尺寸。小型圖片的處理速度可以更快,因此為了縮短延遲時間,以較低解析度拍照,但請留意上方的準確性規定,並確保拍攝主體的臉部盡可能涵蓋最多圖片。另請參閱改善即時效能的訣竅。
影像失焦也可能影響準確度。如未取得可接受的結果,請要求使用者重新拍攝圖片。
相對於攝影機的臉部方向,也可能會影響 ML Kit 偵測到的臉部特徵。請參閱「臉部偵測概念」一文。
1. 設定臉部偵測工具
將臉部偵測功能套用至圖片前,如要變更臉孔偵測工具的預設設定,請使用FaceDetectorOptions
物件指定這些設定。您可以變更下列設定:
設定 | |
---|---|
performanceMode |
fast (預設) | accurate 偵測臉孔時,偏好速度或準確度。 |
landmarkMode |
none (預設) | all 是否嘗試偵測所有偵測到的臉孔 (眼睛、耳朵、鼻子、臉頰、嘴巴)。 |
contourMode |
none (預設) | all 是否偵測臉部特徵的輪廓。系統只會偵測圖片中最顯眼的臉孔。 |
classificationMode |
none (預設) | all 是否要將臉孔分類為「微笑」和「眼睛張開」等類別。 |
minFaceSize |
CGFloat (預設值:0.1 )設定所需的最小臉孔尺寸,以標題寬度與圖片寬度的比例表示。 |
isTrackingEnabled |
false (預設) | true 指定是否指派臉孔 ID,可用於追蹤多張圖片的臉孔。 請注意,如果啟用輪廓偵測功能,系統就只會偵測到一張臉孔,因此臉部追蹤功能不會產生實用的結果。因此,為了加快偵測速度,請勿同時啟用輪廓偵測和臉部追蹤。 |
例如,您可以像下列其中一個範例一樣建構 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. 準備輸入圖片
如要偵測圖片中的臉孔,請使用process(_:completion:)
或 results(in:)
方法,將圖片做為 UIImage
或 CMSampleBufferRef
傳遞至 FaceDetector
:
使用 UIImage
或 CMSampleBuffer
建立 VisionImage
物件。
如果您使用 UIImage
,請按照下列步驟操作:
- 使用
UIImage
建立VisionImage
物件。請務必指定正確的.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; } }
- 使用
CMSampleBuffer
物件和方向建立VisionImage
物件: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
模式 (預設為啟用)。建議你以較低的解析度拍照。不過,請注意此 API 的圖片尺寸規定。
- 如要處理影片畫面,請使用偵測工具的
results(in:)
同步 API。從AVCaptureVideoDataOutputSampleBufferDelegate
的captureOutput(_, didOutput:from:)
函式呼叫此方法,即可同步取得指定影片畫面的結果。將AVCaptureVideoDataOutput
的alwaysDiscardsLateVideoFrames
保留為true
,藉此調節對偵測工具的呼叫次數。如果在偵測工具執行期間提供新的影片畫面,該影格將遭到捨棄。 - 如果您使用偵測工具的輸出內容將輸入圖片上的圖形重疊,請先從 ML Kit 取得結果,然後再在單一步驟算繪影像和重疊。這樣一來,您只會在每個已處理的輸入影格轉譯一次螢幕介面。如需範例,請參閱 ML Kit 快速入門導覽課程範例中的 updatePreviewOverlayViewWithLastFrame。