你可以使用 ML Kit 偵測圖片和影片中的臉孔。
事前準備
- 如果您尚未將 Firebase 加入應用程式,請按照入門指南中的步驟進行。
- 在 Podfile 中加入 ML Kit 程式庫:
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'
安裝或更新專案的 Pod 後,請務必使用.xcworkspace
開啟 Xcode 專案。 - 在應用程式中匯入 Firebase:
Swift
import Firebase
Objective-C
@import Firebase;
輸入圖片規範
為了讓 ML Kit 準確偵測臉孔,輸入圖片必須包含以充足像素資料表示的臉孔。一般來說,您要在圖片中偵測的每個臉孔都必須至少為 100 x 100 像素。如要偵測臉孔的等差,ML Kit 需要較高的輸入解析度:每個臉部至少應為 200 x 200 像素。
如要在即時應用程式中偵測臉孔,建議您也考量輸入圖片的整體尺寸。系統可更快處理較小的圖片,因此為了縮短延遲時間,請盡量以較低的解析度拍攝圖片 (請注意上述準確率規定),並確保拍攝主體的臉孔盡可能佔滿。另請參閱「即時效能改善提示」。
圖片焦點不佳可能會降低準確性。如果您仍未取得可接受的結果,請嘗試要求使用者重新拍攝圖片。
相對於攝影機的臉部方向,也可能會影響 ML Kit 偵測到的臉部特徵。請參閱「臉部偵測概念」一文。
1. 設定臉部偵測工具
如要在圖片上套用臉部偵測功能,如要變更任何臉部偵測工具的預設設定,請使用VisionFaceDetectorOptions
物件指定這些設定。您可以變更下列設定:
設定 | |
---|---|
performanceMode |
fast (預設) | accurate 改善偵測臉孔的速度或精確度。 |
landmarkMode |
none (預設) | all 是否要嘗試偵測所有偵測到的臉孔「地標」,包括眼睛、耳朵、鼻子、臉頰、嘴巴。 |
contourMode |
none (預設) | all 是否偵測臉部特徵的輪廓。系統只會針對圖片中最顯眼的臉孔偵測輪廓。 |
classificationMode |
none (預設) | all 是否將臉孔分類,例如「微笑」和「睜開雙眼」。 |
minFaceSize |
CGFloat (預設:0.1 )待偵測臉孔的最小尺寸 (相對於圖片)。 |
isTrackingEnabled |
false (預設) | true 是否指派臉孔 ID,這組 ID 可用於追蹤圖片中的臉孔。 請注意,啟用輪廓偵測功能後,系統只會偵測到一個臉孔,因此臉部追蹤功能無法產生實用的結果。因此,如要加快偵測速度,請勿同時啟用輪廓偵測和臉部追蹤功能。 |
例如,您可以依照下列範例建構 VisionFaceDetectorOptions
物件:
Swift
// 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
Objective-C
// 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
的形式傳遞至 VisionFaceDetector
的 detect(in:)
方法:
- 取得
VisionFaceDetector
的例項:Swift
lazy var vision = Vision.vision() let faceDetector = vision.faceDetector(options: options)
Objective-C
FIRVision *vision = [FIRVision vision]; FIRVisionFaceDetector *faceDetector = [vision faceDetector]; // Or, to change the default settings: // FIRVisionFaceDetector *faceDetector = // [vision faceDetectorWithOptions:options];
-
使用
UIImage
或CMSampleBufferRef
建立VisionImage
物件。如何使用
UIImage
:- 視需要旋轉圖片,讓
imageOrientation
屬性為.up
。 - 使用正確旋轉的
UIImage
建立VisionImage
物件。請勿指定任何旋轉中繼資料,必須使用預設值.topLeft
。Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
如何使用
CMSampleBufferRef
:-
建立
VisionImageMetadata
物件,指定CMSampleBufferRef
緩衝區中圖片資料的方向。如何取得圖片方向:
Swift
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 } }
Objective-C
- (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; } }
然後,建立中繼資料物件:
Swift
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Objective-C
FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init]; AVCaptureDevicePosition cameraPosition = AVCaptureDevicePositionBack; // Set to the capture device you used. metadata.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
- 使用
CMSampleBufferRef
物件和旋轉中繼資料建立VisionImage
物件:Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- 視需要旋轉圖片,讓
-
接著,將圖片傳遞至
detect(in:)
方法:Swift
faceDetector.process(visionImage) { faces, error in guard error == nil, let faces = faces, !faces.isEmpty else { // ... return } // Faces detected // ... }
Objective-C
[faceDetector detectInImage:image completion:^(NSArray<FIRVisionFace *> *faces, NSError *error) { if (error != nil) { return; } else if (faces != nil) { // Recognized faces } }];
3. 取得系統偵測到的臉孔資訊
如果臉部偵測作業成功,臉部偵測工具會將VisionFace
物件陣列傳遞至完成處理常式。每個 VisionFace
物件都代表在圖片中偵測到的臉孔。您可以在輸入圖片中取得每個臉孔的邊界座標,以及您設定臉部偵測工具尋找的其他資訊。例如:
Swift
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 } }
Objective-C
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
模式 (預設為啟用)。建議以較低的解析度拍攝圖片。不過,也請注意這個 API 的圖片尺寸規定。
- 限制對偵測工具的呼叫。如果在偵測工具執行時有新的影片影格,請捨棄影格。
- 如果您使用偵測工具的輸出內容,在輸入圖片上疊加圖像,請先從 ML Kit 取得結果,然後透過一個步驟算繪圖像和疊加層。如此一來,每個輸入影格都只會算繪到顯示介面一次。如需範例,請參閱展示範例應用程式中的 previewOverlayView 和 FIRDetectionOverlayView 類別。