IOS人臉識別開發入門教程--人臉檢測篇
引言
人臉識別當前比較熱門的技術,作為開發者的我們,如果不實現人臉識別的功能就太Low了,從頭開始發明輪子不可取,我們可以用很多現成的人臉識別技術來實現。
當前的人臉識別技術分為WEBAPI和SDK呼叫兩種方式,WEBAPI需要實時聯網,SDK呼叫可以離線使用。
本次我們使用的虹軟免費開發的離線版本的SDK,離線版本的特點就是我們可以隨時在本地使用,而不用擔心聯網的問題。最生要的是SDK免費,也就是說不用擔心後面使用著使用著收費的問題。
有關本文章的示例程式碼,請到http://download.csdn.net/download/feishixin/9954948 下載示例專案,下載後,需要把http://www.arcsoft.com.cn/ai/arcface.html 下載的.a檔案引入到專案中。你也可以到http://www.arcsoft.com.cn/bbs/forum.php?mod=forumdisplay&fid=45 下載其它語言的demo。
專案目標
我們需要實現一個人臉識別功能,通過呼叫手機的前置設想頭,識別攝像頭中實時拍到的人臉資訊。如果人臉資訊已經在人臉庫中,則顯示出人臉的識別後的資料資訊,如果不在,提示未註冊,並詢問使用者是否把人臉資訊加入到人臉庫中。
人臉註冊
人臉註冊是指,我們在輸入完使用者名稱和密碼後,呼叫攝像頭,把儲存的人臉特徵和系統中的一個使用者相關聯。
人臉檢測是指一個場景,在這個場景中,檢測是否存在一個人臉,如果存在,它檢測的方式是通過人臉的關鍵點資料來進行定位的,通常的人臉檢測程式中,人臉的檢測結果會返回一個框。人臉識別引擎通過對框內的圖片進行分析,提取被稱為人臉特徵點的資料並存入資料庫,這個過程稱為人臉資訊註冊,人臉資訊註冊後,在識別到新的人臉後,再呼叫人臉識別引擎,通過對比庫中的人臉資訊,獲得不同人臉的相似度值,就完成了人臉識別功能。
準備工作
在開始之前,我們需要先下載我們用到的IOS庫,我們使用的是虹軟的人臉識別庫,你可以在 http://www.arcsoft.com.cn/ai/arcface.html 下載最新的版本,下載後我們得到了三個包,分別是
face_tracking用於人臉資訊跟蹤,它用來定位並追蹤面部區域位置,隨著人物臉部位置的變化能夠快速定位人臉位置
face_detection用於靜態照片中的人臉檢測。人臉檢測是人臉技術的基礎,它檢測並且定位到影像(圖片或者視訊)中的人臉。
face_recognition,face_tracking,face_detection
face_recognition用於人臉特徵點提取及人臉資訊比對,其中FR根據不同的應用場景又分為1:1和1:N 。(1:1)主要用來分析兩張臉的相似度,多用於使用者認證及身份驗證。
(1:N)針對一張輸入的人臉,在已建立的人臉資料庫中檢索相似的人臉。
我們在本demo中使用的是1:1
由於FR的功能需要FD或者FT的檢測資料,因此的下載包中是包含所有的三個庫的。
這三包的結構基本相同,我們需要把它們解壓。
- doc 此目錄中存放GUIDE文件,是說明文件,裡面介紹了公開發布的一些API,並提供了示例程式碼。不過,這個示例程式碼比較簡單,如果你沒有經驗,是很難理解的。
- inc 儲存的是供引用的庫,一般是當前API對應的標頭檔案
- lib 共享庫,這裡面放的是SDK編譯後的.a檔案。你需要把它們全部引用到專案中。
- platform 包括兩個資料夾,其中inc為平臺相關的標頭檔案,這個是我們的SDK要引用到的,因此必須要包含進去,具體的作用可以參見各個檔案的註釋。lib是mpbase庫,也需要把它包含到我們專案中。
- sampleCode 示例程式碼
建立專案
我們的專案比較簡單,所以我們就建立普通的SingleViewApplaction.
設計檢視
檢視很簡單,由於我們主要是識別人臉,我們使用一個子檢視來顯示人臉資訊資料。
主檢視
顯示人臉部分我們直接使用自定義的OPENGL的View,因為這裡是一個視訊識別的功能,所以我們需要使用OPENGL/硬體加速,以實現顯示的快速和高效。
這個是一個自定義的View。你可以先下載本教程的原始碼,在GlView中找到這部分程式碼並把它拖到我們的專案中。
開啟設計器,找到Main.storyboard.拉控制元件到Storboard視窗,Class選擇我們使用的GLView.
設定檢視高度和寬度為填滿整個視窗。
子檢視
我們還需要一個子檢視用於顯示識別的框。這個檢視比較簡單,我們新增一個Controller,Class選擇預設類。
這裡面我們可以定義幾個Label是用於顯示人臉識別資訊,類似於美國大片中的那些顯示資訊的效果,比如 劉德華 CIA-HongKong之類
我們後面甚至可以將系統中註冊的人臉顯示出來,供人臉比對。不過這又需要另外一個子檢視,有興趣的讀者可以自行嘗試
實現業務邏輯
首先,我們開啟預設的ViewController
我們在.h檔案中增加GlView.h的標頭檔案。
#import "GLView.h"
定義OpenGL檢視介面屬性,這個是我們的主檢視。
@property (weak, nonatomic) IBOutlet GLView *glView;
用於存放人臉特徵小試圖的集合
@property (nonatomic, strong) NSMutableArray* arrayAllFaceRectView;
定義影象視訊的處理大小,由於是手機使用,我們使用720p的大小就夠了
#define IMAGE_WIDTH 720
#define IMAGE_HEIGHT 1280
找到ViewDidLoad方法,我們在這裡定義業務邏輯。
我們準備使用手機的前置攝像頭的視訊,並且希望我們的人臉框資訊和手機的螢幕方向一致。
//根據當前手機的方向自動確認影象識別的方向
UIInterfaceOrientation uiOrientation = [[UIApplication sharedApplication] statusBarOrientation];
AVCaptureVideoOrientation videoOrientation = (AVCaptureVideoOrientation)uiOrientation;
我們希望攝像頭的視訊能夠充滿全屏,獲得一種良好的體驗效果。
這部分的程式碼具有代表性,但邏輯比較簡單。
//計算OpenGL視窗大小
CGSize sizeTemp = CGSizeZero;
if(uiOrientation == UIInterfaceOrientationPortrait || uiOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
sizeTemp.width = MIN(IMAGE_WIDTH, IMAGE_HEIGHT);
sizeTemp.height = MAX(IMAGE_WIDTH, IMAGE_HEIGHT);
}
else
{
sizeTemp.width = MAX(IMAGE_WIDTH, IMAGE_HEIGHT);
sizeTemp.height = MIN(IMAGE_WIDTH, IMAGE_HEIGHT);
}
CGFloat fWidth = self.view.bounds.size.width;
CGFloat fHeight = self.view.bounds.size.height;
[Utility CalcFitOutSize:sizeTemp.width oldH:sizeTemp.height newW:&fWidth newH:&fHeight];
self.glView.frame = CGRectMake((self.view.bounds.size.width-fWidth)/2,(self.view.bounds.size.width-fWidth)/2,fWidth,fHeight);
[self.glView setInputSize:sizeTemp orientation:videoOrientation];
初始化人臉識別子檢視資料
self.arrayAllFaceRectView = [NSMutableArray arrayWithCapacity:0];
//TODO:監視攝像頭變化。檢測攝像頭中的人臉資訊
處理攝像頭互動邏輯
IOS提供了AVFundation用於處理視訊和音訊捕捉相關的工作,其中的AVCaptureSession是AVFoundation的核心類,用於捕捉視訊和音訊,協調視訊和音訊的輸入和輸出流
AFCameraController
為了方便處理這些過程,我們把這些部分單獨獨立為一個類。我們來定義一個類
AFCameraController
你可以通過xcode的新增檔案,選擇cocoa Touch Class,填寫類名和對應的父類名稱,生成此類。
@interface AFCameraController : NSObject
- (BOOL) setupCaptureSession:(AVCaptureVideoOrientation)videoOrientation;
- (void) startCaptureSession;
- (void) stopCaptureSession;
@end
AVCaptureVideoDataOutputSampleBufferDelegate
這個委託包含一個回撥函式,它提供了處理視訊的介面機制,視訊是由業務邏輯直接處理的,我們需要把AVCapptureSession中的委託AVCaptureVideoDataOutputSampleBufferDelegate重新定義出來
@protocol AFCameraControllerDelegate <NSObject>
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection;
@end
在類定義中增加委託
@property (nonatomic, weak) id <AFCameraControllerDelegate> delegate;
定義居部變數
AVCaptureSession *captureSession;
AVCaptureConnection *videoConnection;
我們來實現setupCaptureSession方法
captureSession = [[AVCaptureSession alloc] init];
[captureSession beginConfiguration];
AVCaptureDevice *videoDevice = [self videoDeviceWithPosition:AVCaptureDevicePositionFront];
AVCaptureDeviceInput *videoIn = [[AVCaptureDeviceInput alloc] initWithDevice:videoDevice error:nil];
if ([captureSession canAddInput:videoIn])
[captureSession addInput:videoIn];
AVCaptureVideoDataOutput *videoOut = [[AVCaptureVideoDataOutput alloc] init];
[videoOut setAlwaysDiscardsLateVideoFrames:YES];
NSDictionary *dic = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
[videoOut setVideoSettings:dic];
/*處理並定義視訊輸出委託處理*/
dispatch_queue_t videoCaptureQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
[videoOut setSampleBufferDelegate:self queue:videoCaptureQueue];
if ([captureSession canAddOutput:videoOut])
[captureSession addOutput:videoOut];
videoConnection = [videoOut connectionWithMediaType:AVMediaTypeVideo];
if (videoConnection.supportsVideoMirroring) {
[videoConnection setVideoMirrored:TRUE];
}
if ([videoConnection isVideoOrientationSupported]) {
[videoConnection setVideoOrientation:videoOrientation];
}
if ([captureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
[captureSession setSessionPreset:AVCaptureSessionPreset1280x720];
}
[captureSession commitConfiguration];
return YES;
在上面的程式碼中我們定義了本地處理setSampleBufferDelegate
因此,我們需要在.m的類名中增加AVCaptureVideoDataOutputSampleBufferDelegate委託處理,程式碼如下所示
@interface AFCameraController ()<AVCaptureVideoDataOutputSampleBufferDelegate>
我們需要實現這個委託對應的處理方法
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
if (connection == videoConnection) {
if (self.delegate && [self.delegate respondsToSelector:@selector(captureOutput:didOutputSampleBuffer:fromConnection:)]) {
[self.delegate captureOutput:captureOutput didOutputSampleBuffer:sampleBuffer fromConnection:connection];
}
}
}
然後我們填寫session的start和stop方法,就比較簡單了
- (void) startCaptureSession
{
if ( !captureSession )
return;
if (!captureSession.isRunning )
[captureSession startRunning];
}
- (void) stopCaptureSession
{
[captureSession stopRunning];
captureSession = nil;
}
新增AFCamaraController引用
讓我們回到業務ViewController類,在.h中增加AFCamaraController.h的引用,並且增加變數camaraController
#import "AFCameraController.h"
...
@property (nonatomic, strong) AFCameraController* cameraController;
在viewDidLoad方法中,增加camaraController的的處理邏輯。
// 利用另外的Controller的方式啟動攝像夈監聽執行緒
self.cameraController = [[AFCameraController alloc]init];
self.cameraController.delegate = self;
[self.cameraController setupCaptureSession:videoOrientation];
[self.cameraController startCaptureSession];
由於我們使用了另外的類,因此我們需要在dealloc方法中主動呼叫uninit的方法來完成記憶體物件的釋放。
- (void)dealloc
{
[self.cameraController stopCaptureSession];
}
我們在AFCameraController定義了委託,用於處理攝像頭獲取視訊後的處理操作。首先和AFCameraController類一樣,我們的ViewController也需要實現AFCameraControllerDelegate委託。
@interface ViewController : UIViewController<AFCameraControllerDelegate>
我們來實現這個委託
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
//獲取影象
//在檢視上顯示捕獲到的影象
//呼叫人臉檢測引擎,得到人臉的範圍
//使用子檢視的方式,顯示捕獲到的人臉資訊,對,還得加上一個框標示人臉的位置
}
看到上面的註釋,是不是覺得這個委託才是我們主角。
構造ASVLOFFSCREEN 結構體
開啟下載的API文件,可以看到視訊處理需要一個結構體ASVLOFFSCREEN,需要處理的影象格式為
ASVL_PAF_NV12視訊格式,是IOS攝像頭提供的preview callback的YUV格式的兩種之一
這個結構體的定義在asvloffscreen.h檔案中。它的定義如下
typedef struct __tag_ASVL_OFFSCREEN
{
MUInt32 u32PixelArrayFormat;
MInt32 i32Width;
MInt32 i32Height;
MUInt8* ppu8Plane[4];
MInt32 pi32Pitch[4];
}ASVLOFFSCREEN, *LPASVLOFFSCREEN;
其中ppu8Plane儲存的是影象的資料。從上面的結構中可知道,要想實現功能,首先得向這個結構體傳遞正確的值。ppu8Plane儲存的就是PixelArrayFormat對應的影象的二制資料資訊
繼續來處理委託,在captureOutput中增加下面的程式碼
CVImageBufferRef cameraFrame = CMSampleBufferGetImageBuffer(sampleBuffer);
int bufferWidth = (int) CVPixelBufferGetWidth(cameraFrame);
int bufferHeight = (int) CVPixelBufferGetHeight(cameraFrame);
LPASVLOFFSCREEN pOffscreenIn = [self offscreenFromSampleBuffer:sampleBuffer];
//顯示採集到的視訊
dispatch_sync(dispatch_get_main_queue(), ^{
[self.glView render:bufferWidth height:bufferHeight yData:pOffscreenIn->ppu8Plane[0] uvData:pOffscreenIn->ppu8Plane[1]];
}
將影象資訊轉為化offscreen
我們來實現offscreenFromSampleBuffer方法
這個方法中通過獲取攝像頭的資料sampleBuffer,構造ASVLOFFSCREEN結構體。
- (LPASVLOFFSCREEN)offscreenFromSampleBuffer:(CMSampleBufferRef)sampleBuffer
{
if (NULL == sampleBuffer)
return NULL;
CVImageBufferRef cameraFrame = CMSampleBufferGetImageBuffer(sampleBuffer);
int bufferWidth = (int) CVPixelBufferGetWidth(cameraFrame);
int bufferHeight = (int) CVPixelBufferGetHeight(cameraFrame);
OSType pixelType = CVPixelBufferGetPixelFormatType(cameraFrame);
CVPixelBufferLockBaseAddress(cameraFrame, 0);
/*判斷是否已經有內容,有內容清空*/
if (_offscreenIn != NULL)
{
if (_offscreenIn->i32Width != bufferWidth || _offscreenIn->i32Height != bufferHeight || ASVL_PAF_NV12 != _offscreenIn->u32PixelArrayFormat) {
[Utility freeOffscreen:_offscreenIn];
_offscreenIn = NULL;
}
}
/*先構造結構體*/
if (_offscreenIn == NULL) {
_offscreenIn = [Utility createOffscreen:bufferWidth height:bufferHeight format:ASVL_PAF_NV12];
}
//獲取camaraFrame資料資訊並複製到ppu8Plane[0]
ASVLOFFSCREEN* pOff = _offscreenIn;
uint8_t *baseAddress0 = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(cameraFrame, 0); // Y
uint8_t *baseAddress1 = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(cameraFrame, 1); // UV
size_t rowBytePlane0 = CVPixelBufferGetBytesPerRowOfPlane(cameraFrame, 0);
size_t rowBytePlane1 = CVPixelBufferGetBytesPerRowOfPlane(cameraFrame, 1);
// YData
if (rowBytePlane0 == pOff->pi32Pitch[0])
{
memcpy(pOff->ppu8Plane[0], baseAddress0, rowBytePlane0*bufferHeight);
}
else
{
for (int i = 0; i < bufferHeight; ++i) {
memcpy(pOff->ppu8Plane[0] + i * bufferWidth, baseAddress0 + i * rowBytePlane0, bufferWidth);
}
}
// uv data
if (rowBytePlane1 == pOff->pi32Pitch[1])
{
memcpy(pOff->ppu8Plane[1], baseAddress1, rowBytePlane1 * bufferHeight / 2);
}
else
{
uint8_t *pPlanUV = pOff->ppu8Plane[1];
for (int i = 0; i < bufferHeight / 2; ++i) {
memcpy(pPlanUV + i * bufferWidth, baseAddress1+ i * rowBytePlane1, bufferWidth);
}
}
CVPixelBufferUnlockBaseAddress(cameraFrame, 0);
return _offscreenIn;
}
在上面的程式碼中我們使用到的createOffscreen是我們定義一個工具類Utility中的方法,它的作用是建立指定大小的Offscreen,並返回指標。
+ (LPASVLOFFSCREEN) createOffscreen:(MInt32) width height:( MInt32) height format:( MUInt32) format
{
ASVLOFFSCREEN* pOffscreen = MNull;
do
{
pOffscreen = (ASVLOFFSCREEN*)malloc(sizeof(ASVLOFFSCREEN));
if(!pOffscreen)
break;
memset(pOffscreen, 0, sizeof(ASVLOFFSCREEN));
pOffscreen->u32PixelArrayFormat = format;
pOffscreen->i32Width = width;
pOffscreen->i32Height = height;
pOffscreen->pi32Pitch[0] = pOffscreen->i32Width; //Y
pOffscreen->pi32Pitch[1] = pOffscreen->i32Width; //UV
pOffscreen->ppu8Plane[0] = (MUInt8*)malloc(height * pOffscreen->pi32Pitch[0] ) ; // Y
memset(pOffscreen->ppu8Plane[0], 0, height * pOffscreen->pi32Pitch[0]);
pOffscreen->ppu8Plane[1] = (MUInt8*)malloc(height / 2 * pOffscreen->pi32Pitch[1]); // UV
memset(pOffscreen->ppu8Plane[1], 0, height * pOffscreen->pi32Pitch[0] / 2);
}while(false);
return pOffscreen;
}
這部分程式碼可以直接拷貝到你的程式中使用,要理解這部分程式碼,需要比較多的圖形影象方面的知識,在本文章中將不再贅述。
接入虹軟人臉檢測引擎
從這裡開始,我們正式接入人臉檢測引擎,我們把人臉相關的功能單獨建一個類AFVideoProcessor。用於編寫和人臉識別SDK相關的程式碼
新增必要的引用
我們可以直接跟蹤示例程式碼來新增必要的引用,因此我們把下載到的SDK中的標頭檔案按需新增引用。
#import "AFVideoProcessor.h"
#import "ammem.h"
#import "merror.h"
#import "arcsoft_fsdk_face_tracking.h"
#import "Utility.h"
#import "AFRManager.h"
#define AFR_DEMO_APP_ID "bCx99etK9Ns4Saou1EbFdC8JMYnMmmLmpw1***"
#define AFR_DEMO_SDK_FT_KEY "FE9XjUgYTNXyBHiapTApnFydX4PpXB2ZaxhvtkD***"
#define AFR_FT_MEM_SIZE 1024*1024*5
上面的APPID和FT KEY,請到下載引擎頁面檢視,你可以在使用者中心的申請歷史中查到你申請到的Key的資訊。
在interface段定義變數
MHandle _arcsoftFT;
MVoid* _memBufferFT;
定義人臉結構體變數
@property(nonatomic,assign) MRECT faceRect;
定義用ASVLOFFSCREEN變數
ASVLOFFSCREEN* _offscreenForProcess;
定義三個主要方法
- (void)initProcessor;
- (void)uninitProcessor;
- (NSArray*)process:(LPASVLOFFSCREEN)offscreen;
initProcessor
此方法用於初始化虹軟引擎,應用程式需要主動呼叫此方法。
- (void)initProcessor
{
_memBufferFT = MMemAlloc(MNull,AFR_FT_MEM_SIZE);
AFT_FSDK_InitialFaceEngine((MPChar)AFR_DEMO_APP_ID, (MPChar)AFR_DEMO_SDK_FT_KEY, (MByte*)_memBufferFT, AFR_FT_MEM_SIZE, &_arcsoftFT, AFT_FSDK_OPF_0_HIGHER_EXT, 16, AFR_FD_MAX_FACE_NUM);
}
注:虹軟這次庫中提供了記憶體操作的一些函式,定義在ammem.h中,我們的程式在需要分配記憶體時,優先呼叫這裡面的方法。
uninitProcessor
此方法用於反初始化引擎,主要是釋放佔用的記憶體。
- (void)uninitProcessor
{
AFT_FSDK_UninitialFaceEngine(_arcsoftFT);
_arcsoftFT = MNull;
if(_memBufferFT != MNull)
{
MMemFree(MNull, _memBufferFT);
_memBufferFT = MNull;
}
}
process 識別人臉位置
這個方法就是識別人臉位置的主要方法,我們可參考API文件中的示例程式碼來完成。
- (NSArray*)process:(LPASVLOFFSCREEN)offscreen
{
MInt32 nFaceNum = 0;
MRECT* pRectFace = MNull;
__block AFR_FSDK_FACEINPUT faceInput = {0};
LPAFT_FSDK_FACERES pFaceResFT = MNull;
AFT_FSDK_FaceFeatureDetect(_arcsoftFT, offscreen, &pFaceResFT);
if (pFaceResFT) {
nFaceNum = pFaceResFT->nFace;
pRectFace = pFaceResFT->rcFace;
}
if (nFaceNum > 0)
{
faceInput.rcFace = pFaceResFT->rcFace[0];
faceInput.lOrient = pFaceResFT->lfaceOrient;
}
NSMutableArray *arrayFaceRect = [NSMutableArray arrayWithCapacity:0];
for (int face=0; face<nFaceNum; face++) {
AFVideoFaceRect *faceRect = [[AFVideoFaceRect alloc] init];
faceRect.faceRect = pRectFace[face];
[arrayFaceRect addObject:faceRect];
}
}
這個方法返回一個陣列,陣列中儲存人臉的識別資訊,程式中可以利用這個資訊來顯示人臉。
如上所述,引入標頭檔案,並定義變數
#import "AFVideoProcessor.h"
@property (nonatomic, strong) AFVideoProcessor* videoProcessor;
在viewDidLoad方法中初始化引擎
self.videoProcessor = [[AFVideoProcessor alloc] init];
[self.videoProcessor initProcessor];
回到captureOutput方法,獲取識別到的人臉資料
NSArray *arrayFaceRect = [self.videoProcessor process:pOffscreenIn];
由於虹軟人臉引擎是支援多個人臉識別的,因此返回給我們的是一個資料,我們需要對每個人臉進行處理顯示,這裡的顯示 是加一個框,並且把我們自定義的子試圖中的資料顯示出來 。所以這裡是一個迴圈。
for (NSUInteger face=self.arrayAllFaceRectView.count; face<arrayFaceRect.count; face++) {
//定位到自定義的View
UIStoryboard *faceRectStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIView *faceRectView = [faceRectStoryboard instantiateViewControllerWithIdentifier:@"FaceRectVideoController"].view;
//我們的檢視需要顯示為綠色的框框
faceRectView.layer.borderColor=[UIColor greenColor].CGColor;
faceRectView.layer.borderWidth=2;
[self.view addSubview:faceRectView];
[self.arrayAllFaceRectView addObject:faceRectView];
}
這裡只是顯示一個框,如果我們的框需要跟蹤到人臉的位置並能自動縮放大小,還需要我們做一些工作。我們需要根據返回的人臉資料來設定view.frame的屬性。
人臉框的定位需要進行一系列簡單的數學計算。也就是將檢視的視窗人臉的視窗大小進行擬合。
程式碼如下:
- (CGRect)dataFaceRect2ViewFaceRect:(MRECT)faceRect
{
CGRect frameFaceRect = {0};
CGRect frameGLView = self.glView.frame;
frameFaceRect.size.width = CGRectGetWidth(frameGLView)*(faceRect.right-faceRect.left)/IMAGE_WIDTH;
frameFaceRect.size.height = CGRectGetHeight(frameGLView)*(faceRect.bottom-faceRect.top)/IMAGE_HEIGHT;
frameFaceRect.origin.x = CGRectGetWidth(frameGLView)*faceRect.left/IMAGE_WIDTH;
frameFaceRect.origin.y = CGRectGetHeight(frameGLView)*faceRect.top/IMAGE_HEIGHT;
return frameFaceRect;
}
我們回到captureOutput針對每一個人臉試圖,來定義顯示
for (NSUInteger face=0; face<arrayFaceRect.count; face++) {
UIView *faceRectView = [self.arrayAllFaceRectView objectAtIndex:face];
faceRectView.hidden = NO;
faceRectView.frame = [self dataFaceRect2ViewFaceRect:((AFVideoFaceRect*)[arrayFaceRect objectAtIndex:face]).faceRect];
NSLog(@"Frame:(%.2f,%.2f,%.2f,%.2f",faceRectView.frame.origin.x,faceRectView.frame.origin.y,faceRectView.frame.size.width,faceRectView.frame.size.height);
}
我們還需要對人臉移出的情況下進行處理,當人臉檢視資料大於識別到的人臉數目時,隱藏顯示
if(self.arrayAllFaceRectView.count >= arrayFaceRect.count)
{
for (NSUInteger face=arrayFaceRect.count; face<self.arrayAllFaceRectView.count; face++) {
UIView *faceRectView = [self.arrayAllFaceRectView objectAtIndex:face];
faceRectView.hidden = YES;
}
}
執行測試
這個時候程式碼終於完成了,你可以執行測試了。效果如下:
應該還是不錯的吧。
當然,這裡面我們只使用最基本的人臉檢測的功能,那個酷炫的資訊框也是介面上硬編碼的。
如果要實現真實的資訊,就需要對人臉特徵進行提取,建立 自己的人臉庫,然後使用人臉識別引擎,對比這些人臉資訊。這些是在虹軟的face_recongation的 SDK中提供的。
提取人臉特徵資訊
face_recongation提取人臉資訊是相當簡單的。
AFR_FSDK_FACEMODEL faceModel = {0};
AFR_FSDK_ExtractFRFeature(_arcsoftFR, pOffscreenForProcess, &faceInput, &faceModel);
提取到的資訊儲存在faceModel結構體中。
typedef struct {
MByte *pbFeature; // The extracted features
MInt32 lFeatureSize; // The size of pbFeature
}AFR_FSDK_FACEMODEL, *LPAFR_FSDK_FACEMODEL;
我們可以通過下面的程式碼獲取到faceModel中的feature資料
AFR_FSDK_FACEMODEL currentFaceModel = {0};
currentFaceModel.pbFeature = (MByte*)[currentPerson.faceFeatureData bytes];
currentFaceModel.lFeatureSize = (MInt32)[currentPerson.faceFeatureData length];
這個結構體中的pbFeature就是人臉特徵資料。我們的程式中需要取到這個資料並將其儲存到的資料庫就可以了。
不同人臉資料之間的比對
不同人臉之間的對比,我們使用的是AFR_FSDK_FacePairMatching介面,我們將 currentFaceModel和refFaceModel進行比對。程式碼如下:
AFR_FSDK_FACEMODEL refFaceModel = {0};
refFaceModel.pbFeature = (MByte*)[person.faceFeatureData bytes];
refFaceModel.lFeatureSize = (MInt32)[person.faceFeatureData length];
MFloat fMimilScore = 0.0;
MRESULT mr = AFR_FSDK_FacePairMatching(_arcsoftFR, &refFaceModel, ¤tFaceModel, &fMimilScore);
MFloat scoreThreshold = 0.56;
if (fMimilScore > scoreThreshold) {
//TODO:處理人臉識別到的邏輯
}
在虹軟人臉比較引擎中,認為0.56是同一個人臉的相對值。高於0.56就認為匹配到了同一個人。關於人臉比對及識別方面的具體處理,請持續關注我的部落格,我會在後面的部落格中來完整介紹實現這個功能的步驟和方法。
後記
基於人臉的技術是人工智慧的重要組成部分,系統中整合人臉可以有效的擴充套件我們程式的現有功能,比如可以根據人臉識別來判斷使用APP的是否是同一個人。在重要的安全領域,甚至我們可以通過對比人臉和身份證資訊是否一致來進行實名認證。正如虹軟人臉識別引擎在介紹頁面中所說的,“未來”已來到 更多實用產品等我們來共同創造!
相關文章
- C#人臉識別入門篇-STEP BY STEP人臉識別--入門篇C#
- 人臉檢測識別,人臉檢測,人臉識別,離線檢測,C#原始碼C#原始碼
- 智慧人臉識別門禁系統開發,人臉識別開鎖流程
- 人臉活體檢測人臉識別:眨眼+張口
- 人臉識別之人臉檢測的重要性
- Python人臉識別微笑檢測Python
- 人臉識別學習筆記一:入門篇筆記
- 人臉識別智慧考勤系統開發_人臉識別考勤管理系統開發
- 從零玩轉人臉識別之RGB人臉活體檢測
- 人臉識別檢測專案實戰
- iOS 人臉關鍵點檢測iOS
- 人臉檢測 二
- opencv 人臉識別OpenCV
- OpenCV — 人臉識別OpenCV
- 人臉識別 -- 活體檢測(張嘴搖頭識別)
- 人臉識別 — 活體檢測(張嘴搖頭識別)
- 人臉檢測(detection)與人臉校準(alignment)
- 人臉識別活體檢測技術理論
- 人臉活體檢測
- 前端人臉檢測指南前端
- 人臉檢測之身份識別你需要的那些事
- 人臉識別之特徵臉方法(Eigenface)特徵
- 前端人臉識別--兩張臉相似度前端
- iOS計算機視覺—人臉識別iOS計算機視覺
- [計算機視覺]人臉應用:人臉檢測、人臉對比、五官檢測、眨眼檢測、活體檢測、疲勞檢測計算機視覺
- opencv視訊人臉檢測OpenCV
- OpenCV 人臉檢測自學(3)OpenCV
- 如何評價美顏api中人臉識別和人臉檢測的準確度?API
- 乾貨 | AI人臉識別之人臉搜尋AI
- 計算機視覺專案-人臉識別與檢測計算機視覺
- 人臉識別技術看這一篇就夠了(附國內人臉識別20強公司)
- python ubuntu dlib人臉識別3-人臉對齊PythonUbuntu
- 保障人臉安全!頂象釋出《人臉識別安全白皮書》
- 人臉識別和手勢識別應用(face++)開發
- 中科視拓免費開放口罩人臉檢測與識別技術
- 人臉檢測的harr檢測函式函式
- 基於開源模型搭建實時人臉識別系統(五):人臉跟蹤模型
- 基於開源模型搭建實時人臉識別系統(四):人臉質量模型