iOS端各方案對UIImage圖片進行人臉檢測耗時統(tǒng)計

前言

  • 本文主要使用iOS平臺下各方案對靜態(tài)圖片的人臉識別進行性能及耗時統(tǒng)計露乏,先附上測試結(jié)果电谣,最后有各實現(xiàn)方案的代碼着绷。

CoreImage方案:

測試數(shù)據(jù)
test_1080x1920.JPG

檢測參數(shù)設(shè)置

image.png

性能消耗情況
CIDetectorAccuracyLow (低精度):

CIDetectorAccuracyHigh(高精度):

image.png

測試數(shù)據(jù)
test_3024x3024.JPG

檢測參數(shù)設(shè)置

image.png

性能消耗情況

CIDetectorAccuracyLow (低精度):


image.png

CIDetectorAccuracyHigh(高精度):


image.png

OpenCV方案:

測試數(shù)據(jù)
test_1080x1920.JPG

檢測參數(shù)設(shè)置
注釋:

    1. scaleFactor為每一個圖像尺度中的尺度參數(shù),默認值為1.1去件。scale_factor參數(shù)可以決定兩個不同大小的窗口掃描之間有多大的跳躍,這個參數(shù)設(shè)置的大扰路,則意味著計算會變快尤溜,但如果窗口錯過了某個大小的人臉,則可能丟失物體汗唱。
    1. minNeighbors參數(shù)為每一個級聯(lián)矩形應(yīng)該保留的鄰近個數(shù)宫莱,默認為3。minNeighbors控制著誤檢測哩罪,默認值為3表明至少有3次重疊檢測授霸,才認為人臉確實存在。
    1. cvSize()指示尋找人臉的最小區(qū)域际插。設(shè)置這個參數(shù)過大碘耳,會以丟失小物體為代價減少計算量。

scaleFactor:1.1
minNeighbors:3
cvSize():Size(30, 30)

image.png

性能消耗情況
人臉檢測器(Haar_1):
[圖片上傳中...(image.png-52e482-1546677776256-0)]

人臉檢測器(快速Haar):

image.png

檢測參數(shù)設(shè)置
scaleFactor:1.1
minNeighbors:1
cvSize():Size(100, 100)

image.png

性能消耗情況
人臉檢測器(Haar_1):

[圖片上傳中...(image.png-813064-1546677870655-0)]

人臉檢測器(快速Haar):

image.png

Vision方案:

系統(tǒng)要求:iOS11及以上

測試數(shù)據(jù)
test_1080x1920.JPG

檢測參數(shù)設(shè)置

image.png

性能消耗情況

image.png

測試數(shù)據(jù)
test_3024x3024.JPG

檢測參數(shù)設(shè)置

image.png

性能消耗情況

image.png

AVFoundation方案:

支持視頻拍攝實時預(yù)覽時進行人臉識別
通過一個特定的AVCaptureOutput類型的AVCaptureMetadataOutput可以實現(xiàn)人臉檢測功能.支持硬件加速以及同時對10個人臉進行實時檢測.

  • PS:
    1.所有方案都已提前初始化好檢測器框弛,單純統(tǒng)計從處理UIImage到輸出檢測結(jié)果的耗時辛辨;

綜述:

CoreImage框架:

支持靜態(tài)圖像人臉識別檢測;
處理過程占CPU較低;高精度:50+%斗搞,低精度:約100%
低精度時識別時間只占幾十毫秒級別绞蹦,但是橫向人臉會檢測失敗(橫向照片可以通過照片的方向信息榜旦,先將照片方向矯正)
高精度識別時間100多ms級別幽七,橫向人臉檢測成功

后續(xù)擴展:可做濾鏡,人臉特征檢測(檢測處理圖片的特性溅呢,如使用來檢測圖片中人臉的眼睛澡屡、嘴巴、等等)咐旧。

OpenCV框架 :

支持靜態(tài)圖像人臉識別檢測驶鹉;
跨平臺;
處理過程占CPU很高; 400+%~500+%
耗時跟參數(shù)的設(shè)置铣墨,識別精度有很大關(guān)系
但是識別參數(shù)可定制化程度高;
橫向檢測失斒衣瘛(可能姿勢不對;

Vision框架:

iOS11起支持;
支持多種圖片類型:
CIImage伊约,NSURL姚淆,NSData,CGImageRef屡律,CVPixelBufferRef(視頻幀取出的圖像格式)腌逢;
處理過程占CPU較低;50+%
耗時和Coreimage的高精度識別差不多超埋,100多毫秒級別
橫向檢測成功

后續(xù)擴展:
人臉特征點搏讶,人臉檢測,二維碼識別霍殴,文字檢測媒惕、識別,目標跟蹤(臉部来庭,矩形和通用模板)妒蔚,矩形檢測。巾腕。

  • 出于識別過程CPU占用率以及識別速度等方面考慮面睛,對相冊的人臉識別篩選需求建議iOS11以上系統(tǒng)采用Vision方案,iOS11以下的系統(tǒng)采用CoreImage的高精度識別方案篩選尊搬。由于沒有足夠的人臉數(shù)據(jù)叁鉴,暫時無法進行識別準確率測試。

附錄

  • KRFaceDetectTool.h //人臉識別工具類
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <CoreImage/CoreImage.h>

NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(NSInteger, KRFaceDetectResolutionType) {
    KRFaceDetectResolutionTypeCoreImage,//靜態(tài)圖像人臉識別
    KRFaceDetectResolutionTypeOpenCV,
    KRFaceDetectResolutionTypeVision,
    KRFaceDetectResolutionTypeAVFoundation//動態(tài)人臉識別
};

@interface KRFaceDetectTool : NSObject

- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

- (instancetype)initWithType:(KRFaceDetectResolutionType)type;

- (void)testForDetectFace;

- (BOOL)detectFaceWithImage:(UIImage*)image;

@end
NS_ASSUME_NONNULL_END
  • KRFaceDetectTool.mm

#import "KRFaceDetectTool.h"

#import <CoreImage/CIDetector.h>
#import "KRCVFaceDetectTool.h"
#import <Vision/Vision.h>
#import "KRGCDExtension.h"

@interface KRFaceDetectTool ()
@property (nonatomic, assign) KRFaceDetectResolutionType type;

//CoreImage
@property (nonatomic, strong) CIDetector *ciDetector;
@property (nonatomic, strong) KRCVFaceDetectTool *cvDetector;
@property (nonatomic, strong) VNImageBasedRequest *visionFaceDetectRequest;

@end

@implementation KRFaceDetectTool

- (instancetype)init {
    NSAssert(NO, @"Please use the given initial method !");
    return nil;
}

+ (instancetype)new {
    NSAssert(NO, @"Please use the given initial method !");
    return nil;
}

- (instancetype)initWithType:(KRFaceDetectResolutionType)type
{
    self = [super init];
    if (self) {
        _type = type;
        [self prepareToDetectWithType:type];
    }
    return self;
}

- (void)dealloc {
    if (self.ciDetector) {
        self.ciDetector = nil;
    }
    if (self.cvDetector) {
        self.cvDetector = nil;
    }
}

- (void)prepareToDetectWithType:(KRFaceDetectResolutionType)type {
    switch (type) {
        case KRFaceDetectResolutionTypeCoreImage:
        {
            if (!self.ciDetector) {
                NSDictionary *options = @{CIDetectorAccuracy:CIDetectorAccuracyLow};
                self.ciDetector = [CIDetector detectorOfType:CIDetectorTypeFace context:nil options:options];
            }
        }
            break;
        case KRFaceDetectResolutionTypeVision:
        {
            void (^completionHandler)(VNRequest *, NSError * _Nullable) = ^(VNRequest *request, NSError * _Nullable error) {
                NSArray *observations = request.results;
                if (request.results.count > 0) {
                    NSLog(@"KRFaceDetectTool: has face!");
                } else {
                    NSLog(@"KRFaceDetectTool: no face!");
                }
            };
            
            self.visionFaceDetectRequest = [[VNDetectFaceRectanglesRequest alloc] initWithCompletionHandler:completionHandler];
        }
            break;
        case KRFaceDetectResolutionTypeOpenCV:
        {
            if (!self.cvDetector) {
                self.cvDetector = [[KRCVFaceDetectTool alloc] initWithType:KRCVFaceXMLTypeHaarcascadeFrontalfaceAlt];
            }
        }
            break;
        case KRFaceDetectResolutionTypeAVFoundation:
        {
            
        }
            break;
        default:
            break;
    }
}

- (BOOL)detectFaceWithImage:(UIImage*)image{
    switch (self.type) {
        case KRFaceDetectResolutionTypeCoreImage:
        {
            CIImage *ciImage = [[CIImage alloc] initWithCGImage:image.CGImage];
            NSArray *features = [self.ciDetector featuresInImage:ciImage];
            if (features.count) {
                return YES;
            }
            return NO;
        }
            break;
        case KRFaceDetectResolutionTypeVision:
        {
            VNImageRequestHandler *visionRequestHandler = [[VNImageRequestHandler alloc] initWithCGImage:image.CGImage options:@{}];
            
            [visionRequestHandler performRequests:@[self.visionFaceDetectRequest] error:nil];
            
        }
            break;
        case KRFaceDetectResolutionTypeOpenCV:
        {
            [self.cvDetector detectFaceWithImage:image];
        }
            break;
        case KRFaceDetectResolutionTypeAVFoundation:
        {
            
        }
            break;
        default:
            break;
    }
    return NO;
}

- (void)testForDetectFace {
    [self prepareToDetectWithType:KRFaceDetectResolutionTypeCoreImage];
    [self prepareToDetectWithType:KRFaceDetectResolutionTypeOpenCV];
    [self prepareToDetectWithType:KRFaceDetectResolutionTypeVision];
    [self prepareToDetectWithType:KRFaceDetectResolutionTypeAVFoundation];
    
    UIImage *testImage = [UIImage imageNamed:@"test_1080x1920.JPG"] ;
    UIImage *testImage2 = [UIImage imageNamed:@"test_3024x3024.JPG"];
    //    testImage2 = [testImage2 imageByRotateLeft90];
    
    void (^coreImageHighAccuracyBlock)(void) = ^{
        @autoreleasepool {
            CIImage *ciImage = [[CIImage alloc] initWithCGImage:testImage.CGImage];
            NSArray *features = [self.ciDetector featuresInImage:ciImage];
            if (features.count) {
                NSLog(@"KRFaceDetectTool: has face!");
            } else {
                NSLog(@"KRFaceDetectTool: no face!");
            }
        }
    };
    
    void (^cvDetectBlock)(void) = ^{
        @autoreleasepool {
            BOOL result = [self.cvDetector detectFaceWithImage:testImage];
            NSLog(@"KRFaceDetectTool: %@",result ? @"has face!": @"no face!");
        }
    };
    
    
    void (^visionDetectBlock)(void) = ^{
        VNImageRequestHandler *visionRequestHandler = [[VNImageRequestHandler alloc] initWithCGImage:testImage.CGImage options:@{}];
        [visionRequestHandler performRequests:@[self.visionFaceDetectRequest] error:nil];
    };
    
    int64_t result = kr_dispatch_benchmark(100, coreImageHighAccuracyBlock);
    NSLog(@"KRFaceDetectTool:xxx coreImageHighAccuracyBlock cost time:%lld",result);

    int64_t result2 = kr_dispatch_benchmark(100, cvDetectBlock);
    NSLog(@"KRFaceDetectTool:xxx cvDetectBlock cost time:%lld",result2);

    int64_t result3 = kr_dispatch_benchmark(100, visionDetectBlock);
    NSLog(@"KRFaceDetectTool:xxx visionDetectBlock cost time:%lld",result3);

}

@end
  • KRCVFaceDetectTool.h //基于opencv的人臉識別工具

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
//OpenCV
#import <opencv2/opencv.hpp>
#import <opencv2/imgproc/types_c.h>
#import <opencv2/imgcodecs/ios.h>

NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(NSInteger, KRCVFaceXMLType) {
    KRCVFaceXMLTypeHaarcascadeFrontalfaceAlt,//對應(yīng)opencv人臉識別xml的文件類型
    KRCVFaceXMLTypeHaarcascadeFrontalfaceAlt2
};

@interface KRCVFaceDetectTool : NSObject
{
    cv::CascadeClassifier faceDetector;
}

- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

- (instancetype)initWithType:(KRCVFaceXMLType)type;

- (BOOL)detectFaceWithImage:(UIImage*)image;

@end
NS_ASSUME_NONNULL_END

  • KRCVFaceDetectTool.mm
#import "KRCVFaceDetectTool.h"

@implementation KRCVFaceDetectTool

- (instancetype)initWithType:(KRCVFaceXMLType)type
{
    self = [super init];
    if (self) {
        [self prepareForDetectInOpenCV:type];
    }
    return self;
}

- (void)dealloc {
    
}

- (void)prepareForDetectInOpenCV:(KRCVFaceXMLType)type {
    switch (type) {
        case KRCVFaceXMLTypeHaarcascadeFrontalfaceAlt:
        {
            NSString* cascadePath = [[NSBundle mainBundle]
                                     pathForResource:@"haarcascade_frontalface_alt"
                                     ofType:@"xml"];
            faceDetector.load([cascadePath UTF8String]);
        }
            break;
        case KRCVFaceXMLTypeHaarcascadeFrontalfaceAlt2:
        {
            NSString* cascadePath = [[NSBundle mainBundle]
                                     pathForResource:@"haarcascade_frontalface_alt2"
                                     ofType:@"xml"];
            faceDetector.load([cascadePath UTF8String]);
        }
            break;
        default:
            break;
    }
}

- (BOOL)detectFaceWithImage:(UIImage*)image {
    cv::Mat cvImage;
    UIImageToMat(image, cvImage);
    if (!cvImage.empty()) {
        //轉(zhuǎn)換為灰度圖
        cv::Mat gray;
        cvtColor(cvImage, gray, CV_BGR2GRAY);
        
        //人臉檢測
        std::vector<cv::Rect> faces;
        faceDetector.detectMultiScale(gray,
                                      faces,
                                      1.1,
                                      1,
                                      0|CV_HAAR_SCALE_IMAGE,
                                      cv::Size(100,100)
                                      );
        
        if (faces.size() > 0) {
            return YES;
        }
        return NO;
    }
    return NO;
}

@end

  • benchmark方法

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

#ifdef __cplusplus
extern "C"
#endif
extern int64_t kr_dispatch_benchmark(size_t count, void (^block)(void));

NS_ASSUME_NONNULL_END

#import "KRGCDExtension.h"

extern uint64_t dispatch_benchmark(size_t count, void (^block)(void));

int64_t kr_dispatch_benchmark(size_t count, void (^block)(void)) {
    return dispatch_benchmark(count, block);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末佛寿,一起剝皮案震驚了整個濱河市幌墓,隨后出現(xiàn)的幾起案子但壮,更是在濱河造成了極大的恐慌,老刑警劉巖常侣,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜡饵,死亡現(xiàn)場離奇詭異,居然都是意外死亡胳施,警方通過查閱死者的電腦和手機溯祸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舞肆,“玉大人焦辅,你說我怎么就攤上這事〈豢瑁” “怎么了筷登?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長哩盲。 經(jīng)常有香客問我前方,道長,這世上最難降的妖魔是什么廉油? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任惠险,我火速辦了婚禮,結(jié)果婚禮上娱两,老公的妹妹穿的比我還像新娘莺匠。我一直安慰自己金吗,他們只是感情好十兢,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著摇庙,像睡著了一般旱物。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卫袒,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天宵呛,我揣著相機與錄音,去河邊找鬼夕凝。 笑死宝穗,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的码秉。 我是一名探鬼主播逮矛,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼转砖!你這毒婦竟也來了须鼎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晋控,沒想到半個月后汞窗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡赡译,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年仲吏,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蝌焚。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜘矢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出综看,到底是詐尸還是另有隱情品腹,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布红碑,位于F島的核電站舞吭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏析珊。R本人自食惡果不足惜羡鸥,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忠寻。 院中可真熱鬧惧浴,春花似錦、人聲如沸奕剃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纵朋。三九已至柿顶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間操软,已是汗流浹背嘁锯。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留聂薪,地道東北人家乘。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像藏澳,于是被迫代替她去往敵國和親仁锯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一笆载、Haar分類器的前世今生 人臉檢測屬于計算機視覺的范疇扑馁,早期人們的主要研究方向是人臉識別涯呻,即根據(jù)人臉來識別人物...
    飛天小小貓閱讀 1,483評論 0 3
  • 人臉檢測是目前所有目標檢測子方向中被研究的最充分的問題之一,它在安防監(jiān)控腻要,人證比對复罐,人機交互,社交和娛樂等方面有很...
    玲小喵閱讀 437評論 0 0
  • 2018-09-04更新: 很久沒有更新文章了雄家,工作之余花時間看了之前寫的這篇文章并運行了之前寫的配套Demo效诅,通...
    Mr_Victory閱讀 27,639評論 49 171
  • 文章作者:Tyan博客:noahsnail.com | CSDN | 簡書 聲明:作者翻譯論文僅為學習,如有侵權(quán)請...
    SnailTyan閱讀 23,270評論 1 35
  • 成為一個媽媽兩年兩個月后的某一天,我突然明白,一個媽媽真正應(yīng)該懂得的是,不要讓自己太累,學會在放手中找到平衡點,...
    柚媽親子心理閱讀 267評論 0 3