此刻要記錄實作內容,才想起先前已寫過一篇,不過那篇是沒有原始碼,然而依舊可參考:[iOS] 使用Vision人臉偵測 (Face Detection Using Vision)。😎
廣告
接下來簡單扼要,寫出核心程式碼~
/**
Theme: Face Detection Using Vision
Compiler: Xcode 12.4
Date: 110/04/14
Author: HappyMan
Blog: https://cg2010studio.com/
*/
#import <Vision/Vision.h>
API_AVAILABLE(ios(11.0))
typedef void(^CompletionHandler)(VNRequest * _Nullable request, NSError * _Nullable error);
-(void)doFaceDetection
{
NSString *name = [NSString stringWithFormat:@"happy group.JPG"];
UIImage *image = [UIImage imageNamed:name];
imageView.image = image;
// 轉換CIImage
CIImage *convertImage = [[CIImage alloc] initWithImage:image];
// 創建處理 RequestHandler
VNImageRequestHandler *detectRequestHandler = [[VNImageRequestHandler alloc] initWithCIImage:convertImage options:@{}];
// 設置回調
CompletionHandler completionHandler = ^(VNRequest *request, NSError * _Nullable error) {
NSArray *observations = request.results;
dispatch_async(dispatch_get_main_queue(), ^{
for (VNFaceObservation *face in observations) {
UIView *view = [self createBoxView:[UIColor redColor]];
view.frame = [self transformFromRect:face.boundingBox toView:self->imageView];
[self->imageView addSubview:view];
}
});
};
// 創建 BaseRequest
VNImageBasedRequest *detectRequest = [[VNDetectFaceRectanglesRequest alloc] initWithCompletionHandler:completionHandler];
// 發送識別請求
[detectRequestHandler performRequests:@[detectRequest] error:nil];
}
-(UIView *)createBoxView:(UIColor *)color
{
UIView *view = [[UIView alloc] init];
view.layer.borderColor = color.CGColor;
view.layer.borderWidth = 2;
view.backgroundColor = [UIColor clearColor];
return view;
}
-(CGRect)transformFromRect:(CGRect)fromRect toView:(UIView *)toView
{
// Convert Vision Frame to UIKit Frame
CGRect toRect = CGRectZero;
toRect.size.width = fromRect.size.width * toView.frame.size.width;
toRect.size.height = fromRect.size.height * toView.frame.size.height;
toRect.origin.y = (toView.frame.size.height) - (toView.frame.size.height * fromRect.origin.y);
toRect.origin.y = toRect.origin.y - toRect.size.height;
toRect.origin.x = fromRect.origin.x * toView.frame.size.width;
return toRect;
}
.
透過上面基本的程式碼,就可以進行其他進階應用,比如偵測人臉是否被「切臉」,有三種狀況:
- 框內
- 框外
- 被框切

經過無數測試,發現神奇的現象,就是不管相片解析度大小,執行一次人臉偵測的時間都差不多呢!
另外人臉佔整張相片太小,也不容易被偵測出來,看來跟它的演算法參數設定有關係。這部分可參考我2011年寫的文章:[OpenCV] 人臉偵測 (Face Detection)。

公司產品想要開發個新穎的功能,就是判斷有無被切臉,以免印製出來遭到用戶退貨~😌
廣告
由於可能要同時偵測大量相片(高達1000張),執行人臉偵測的時間就顯得很重要,因為會影響使用者體驗。這時候就要有所取捨,需要在使用者體驗與亮眼功能取得平衡!
- 目前新增的功能是做到不太影響原本體驗,來默默人臉偵測,好心提示有無切臉。
- 若要掃描整份專案,可以在點「加入購物車」時,進行所有相片框偵測人臉。
- 此時有兩種進行情況:
- 1. 若「必要」,則需要擋UI,等到所有相片偵測結束,才能進行下單
類似偵測到「相片遺失」 - 2. 若「非必要」,則不需要擋UI,不等到所有相片偵測結束,就能進行下單
類似偵測到「縮放比例過大,不符合印製需求」 - 考量偵測人臉時間,處理單張相片:
- iPhone 8,不分相片尺寸,平均處理時間:0.3s
- iPhone 6,不分相片尺寸,平均處理時間:0.6s
- 若以「同步」進行人臉偵測,處理最大數量情況1000張相片
- iPhone 8,不分相片尺寸,平均處理時間:300s
- iPhone 6,不分相片尺寸,平均處理時間:600s
- 若以「非同步」進行人臉偵測,處理最大數量情況1000張相片
- iPhone 8,不分相片尺寸,處理時間約:146s
- iPhone 6,不分相片尺寸,處理時間約:432s
- 接著若偵測到有被切頭,需要如何提示用戶,並快速讓用戶找到該相片,相片數量大不好找尋。
- 於是會增加完稿時間與影響下單體驗。也許可以做個「選擇性」讓用戶看是否要進行所有相片人臉偵測有無切臉。
廣告
隨意留個言吧:)~