鍍金池/ 教程/ iOS/ 基于 OpenCV 的人臉識別
與四軸無人機(jī)的通訊
在沙盒中編寫腳本
結(jié)構(gòu)體和值類型
深入理解 CocoaPods
UICollectionView + UIKit 力學(xué)
NSString 與 Unicode
代碼簽名探析
測試
架構(gòu)
第二期-并發(fā)編程
Metal
自定義控件
iOS 中的行為
行為驅(qū)動開發(fā)
Collection View 動畫
截圖測試
MVVM 介紹
使 Mac 應(yīng)用數(shù)據(jù)腳本化
一個完整的 Core Data 應(yīng)用
插件
字符串
為 iOS 建立 Travis CI
先進(jìn)的自動布局工具箱
動畫
為 iOS 7 重新設(shè)計 App
XPC
從 NSURLConnection 到 NSURLSession
Core Data 網(wǎng)絡(luò)應(yīng)用實(shí)例
GPU 加速下的圖像處理
自定義 Core Data 遷移
子類
與調(diào)試器共舞 - LLDB 的華爾茲
圖片格式
并發(fā)編程:API 及挑戰(zhàn)
IP,TCP 和 HTTP
動畫解釋
響應(yīng)式 Android 應(yīng)用
初識 TextKit
客戶端
View-Layer 協(xié)作
回到 Mac
Android
Core Image 介紹
自定義 Formatters
Scene Kit
調(diào)試
項(xiàng)目介紹
Swift 的強(qiáng)大之處
測試并發(fā)程序
Android 通知中心
調(diào)試:案例學(xué)習(xí)
從 UIKit 到 AppKit
iOS 7 : 隱藏技巧和變通之道
安全
底層并發(fā) API
消息傳遞機(jī)制
更輕量的 View Controllers
用 SQLite 和 FMDB 替代 Core Data
字符串解析
終身學(xué)習(xí)的一代人
視頻
Playground 快速原型制作
Omni 內(nèi)部
同步數(shù)據(jù)
設(shè)計優(yōu)雅的移動游戲
繪制像素到屏幕上
相機(jī)與照片
音頻 API 一覽
交互式動畫
常見的后臺實(shí)踐
糟糕的測試
避免濫用單例
數(shù)據(jù)模型和模型對象
Core Data
字符串本地化
View Controller 轉(zhuǎn)場
照片框架
響應(yīng)式視圖
Square Register 中的擴(kuò)張
DTrace
基礎(chǔ)集合類
視頻工具箱和硬件加速
字符串渲染
讓東西變得不那么糟
游戲中的多點(diǎn)互聯(lián)
iCloud 和 Core Data
Views
虛擬音域 - 聲音設(shè)計的藝術(shù)
導(dǎo)航應(yīng)用
線程安全類的設(shè)計
置換測試: Mock, Stub 和其他
Build 工具
KVC 和 KVO
Core Image 和視頻
Android Intents
在 iOS 上捕獲視頻
四軸無人機(jī)項(xiàng)目
Mach-O 可執(zhí)行文件
UI 測試
值對象
活動追蹤
依賴注入
Swift
項(xiàng)目管理
整潔的 Table View 代碼
Swift 方法的多面性
為什么今天安全仍然重要
Core Data 概述
Foundation
Swift 的函數(shù)式 API
iOS 7 的多任務(wù)
自定義 Collection View 布局
測試 View Controllers
訪談
收據(jù)驗(yàn)證
數(shù)據(jù)同步
自定義 ViewController 容器轉(zhuǎn)場
游戲
調(diào)試核對清單
View Controller 容器
學(xué)無止境
XCTest 測試實(shí)戰(zhàn)
iOS 7
Layer 中自定義屬性的動畫
第一期-更輕量的 View Controllers
精通 iCloud 文檔存儲
代碼審查的藝術(shù):Dropbox 的故事
GPU 加速下的圖像視覺
Artsy
照片擴(kuò)展
理解 Scroll Views
使用 VIPER 構(gòu)建 iOS 應(yīng)用
Android 中的 SQLite 數(shù)據(jù)庫支持
Fetch 請求
導(dǎo)入大數(shù)據(jù)集
iOS 開發(fā)者的 Android 第一課
iOS 上的相機(jī)捕捉
語言標(biāo)簽
同步案例學(xué)習(xí)
依賴注入和注解,為什么 Java 比你想象的要好
編譯器
基于 OpenCV 的人臉識別
玩轉(zhuǎn)字符串
相機(jī)工作原理
Build 過程

基于 OpenCV 的人臉識別

一點(diǎn)背景知識

OpenCV 是一個開源的計算機(jī)視覺和機(jī)器學(xué)習(xí)庫。它包含成千上萬優(yōu)化過的算法,為各種計算機(jī)視覺應(yīng)用提供了一個通用工具包。根據(jù)這個項(xiàng)目的關(guān)于頁面,OpenCV 已被廣泛運(yùn)用在各種項(xiàng)目上,從谷歌街景的圖片拼接,到交互藝術(shù)展覽的技術(shù)實(shí)現(xiàn)中,都有 OpenCV 的身影。

OpenCV 起始于 1999 年 Intel 的一個內(nèi)部研究項(xiàng)目。從那時起,它的開發(fā)就一直很活躍。進(jìn)化到現(xiàn)在,它已支持如 OpenCL 和 OpenGL 等現(xiàn)代技術(shù),也支持如 iOS 和 Android 等平臺。

1999 年,半條命發(fā)布后大紅大熱。Intel 奔騰 3 處理器是當(dāng)時最高級的 CPU,400-500 MHZ 的時鐘頻率已被認(rèn)為是相當(dāng)快。2006 年 OpenCV 1.0 版本發(fā)布的時候,當(dāng)時主流 CPU 的性能也只和 iPhone 5 的 A6 處理器相當(dāng)。盡管計算機(jī)視覺從傳統(tǒng)上被認(rèn)為是計算密集型應(yīng)用,但我們的移動設(shè)備性能已明顯地超出能夠執(zhí)行有用的計算機(jī)視覺任務(wù)的閾值,帶著攝像頭的移動設(shè)備可以在計算機(jī)視覺平臺上大有所為。

在本文中,我會從一個 iOS 開發(fā)者的視角概述一下 OpenCV,并介紹一點(diǎn)基礎(chǔ)的類和概念。隨后,會講到如何集成 OpenCV 到你的 iOS 項(xiàng)目中以及一些 Objective-C++ 基礎(chǔ)知識。最后,我們會看一個 demo 項(xiàng)目,看看如何在 iOS 設(shè)備上使用 OpenCV 實(shí)現(xiàn)人臉檢測與人臉識別。

OpenCV 概述

概念

OpenCV 的 API 是 C++ 的。它由不同的模塊組成,這些模塊中包含范圍極為廣泛的各種方法,從底層的圖像顏色空間轉(zhuǎn)換到高層的機(jī)器學(xué)習(xí)工具。

使用 C++ API 并不是絕大多數(shù) iOS 開發(fā)者每天都做的事,你需要使用 Objective-C++ 文件來調(diào)用 OpenCV 的函數(shù)。 也就是說,你不能在 Swift 或者 Objective-C 語言內(nèi)調(diào)用 OpenCV 的函數(shù)。 這篇 OpenCV 的 iOS 教程告訴你只要把所有用到 OpenCV 的類的文件后綴名改為 .mm 就行了,包括視圖控制器類也是如此。這么干或許能行得通,卻不是什么好主意。正確的方式是給所有你要在 app 中使用到的 OpenCV 功能寫一層 Objective-C++ 封裝。這些 Objective-C++ 封裝把 OpenCV 的 C++ API 轉(zhuǎn)化為安全的 Objective-C API,以方便地在所有 Objective-C 類中使用。走封裝的路子,你的工程中就可以只在這些封裝中調(diào)用 C++ 代碼,從而避免掉很多讓人頭痛的問題,比如直接改文件后綴名會因?yàn)樵阱e誤的文件中引用了一個 C++ 頭文件而產(chǎn)生難以追蹤的編譯錯誤。

OpenCV 聲明了命名空間 cv,因此 OpenCV 的類的前面會有個 cv:: 前綴,就像 cv::Mat、 cv::Algorithm 等等。你也可以在 .mm 文件中使用 using namespace cv 來避免在一堆類名前使用 cv:: 前綴。但是,在某些類名前你必須使用命名空間前綴,比如 cv::Rectcv::Point,因?yàn)樗鼈儠x在 MacTypes.h 中的 RectPoint 相沖突。盡管這只是個人偏好問題,我還是偏向在任何地方都使用 cv:: 以保持一致性。

模塊

下面是在官方文檔中列出的最重要的模塊。

  • core:簡潔的核心模塊,定義了基本的數(shù)據(jù)結(jié)構(gòu),包括稠密多維數(shù)組 Mat 和其他模塊需要的基本函數(shù)。
  • imgproc:圖像處理模塊,包括線性和非線性圖像濾波、幾何圖像轉(zhuǎn)換 (縮放、仿射與透視變換、一般性基于表的重映射)、顏色空間轉(zhuǎn)換、直方圖等等。
  • video:視頻分析模塊,包括運(yùn)動估計、背景消除、物體跟蹤算法。
  • calib3d:包括基本的多視角幾何算法、單體和立體相機(jī)的標(biāo)定、對象姿態(tài)估計、雙目立體匹配算法和元素的三維重建。
  • features2d:包含了顯著特征檢測算法、描述算子和算子匹配算法。
  • objdetect:物體檢測和一些預(yù)定義的物體的檢測 (如人臉、眼睛、杯子、人、汽車等)。
  • ml:多種機(jī)器學(xué)習(xí)算法,如 K 均值、支持向量機(jī)和神經(jīng)網(wǎng)絡(luò)。
  • highgui:一個簡單易用的接口,提供視頻捕捉、圖像和視頻編碼等功能,還有簡單的 UI 接口 (iOS 上可用的僅是其一個子集)。
  • gpu:OpenCV 中不同模塊的 GPU 加速算法 (iOS 上不可用)。
  • ocl:使用 OpenCL 實(shí)現(xiàn)的通用算法 (iOS 上不可用)。
  • 一些其它輔助模塊,如 Python 綁定和用戶貢獻(xiàn)的算法。

基礎(chǔ)類和操作

OpenCV 包含幾百個類。為簡便起見,我們只看幾個基礎(chǔ)的類和操作,進(jìn)一步閱讀請參考全部文檔。過一遍這幾個核心類應(yīng)該足以對這個庫的機(jī)理產(chǎn)生一些感覺認(rèn)識。

cv::Mat

cv::Mat 是 OpenCV 的核心數(shù)據(jù)結(jié)構(gòu),用來表示任意 N 維矩陣。因?yàn)閳D像只是 2 維矩陣的一個特殊場景,所以也是使用 cv::Mat 來表示的。也就是說,cv::Mat 將是你在 OpenCV 中用到最多的類。

一個 cv::Mat 實(shí)例的作用就像是圖像數(shù)據(jù)的頭,其中包含著描述圖像格式的信息。圖像數(shù)據(jù)只是被引用,并能為多個 cv::Mat 實(shí)例共享。OpenCV 使用類似于 ARC 的引用計數(shù)方法,以保證當(dāng)最后一個來自 cv::Mat 的引用也消失的時候,圖像數(shù)據(jù)會被釋放。圖像數(shù)據(jù)本身是圖像連續(xù)的行的數(shù)組 (對 N 維矩陣來說,這個數(shù)據(jù)是由連續(xù)的 N-1 維數(shù)據(jù)組成的數(shù)組)。使用 step[] 數(shù)組中包含的值,圖像的任一像素地址都可通過下面的指針運(yùn)算得到:

uchar *pixelPtr = cvMat.data + rowIndex * cvMat.step[0] + colIndex * cvMat.step[1]

每個像素的數(shù)據(jù)格式可以通過 type() 方法獲得。除了常用的每通道 8 位無符號整數(shù)的灰度圖 (1 通道,CV_8UC1) 和彩色圖 (3 通道,CV_8UC3),OpenCV 還支持很多不常用的格式,例如 CV_16SC3 (每像素 3 通道,每通道使用 16 位有符號整數(shù)),甚至 CV_64FC4 (每像素 4 通道,每通道使用 64 位浮點(diǎn)數(shù))。

cv::Algorithm

Algorithm 是 OpenCV 中實(shí)現(xiàn)的很多算法的抽象基類,包括將在我們的 demo 工程中用到的 FaceRecognizer。它提供的 API 與蘋果的 Core Image 框架中的 CIFilter 有些相似之處。創(chuàng)建一個 Algorithm 的時候使用算法的名字來調(diào)用 Algorithm::create(),并且可以通過 get()set()方法來獲取和設(shè)置各個參數(shù),這有點(diǎn)像是鍵值編碼。另外,Algorithm 從底層就支持從/向 XML 或 YAML 文件加載/保存參數(shù)的功能。

在 iOS 上使用 OpenCV

添加 OpenCV 到你的工程中

集成 OpenCV 到你的工程中有三種方法:

  • 使用 CocoaPods 就好: pod "OpenCV"。
  • 下載官方 iOS 框架發(fā)行包,并把它添加到工程里。
  • GitHub 拉下代碼,并根據(jù)教程自己編譯 OpenCV 庫。

Objective-C++

如前面所說,OpenCV 是一個 C++ 的 API,因此不能直接在 Swift 和 Objective-C 代碼中使用,但能在 Objective-C++ 文件中使用。

Objective-C++ 是 Objective-C 和 C++ 的混合物,讓你可以在 Objective-C 類中使用 C++ 對象。clang 編譯器會把所有后綴名為 .mm 的文件都當(dāng)做是 Objective-C++。一般來說,它會如你所期望的那樣運(yùn)行,但還是有一些使用 Objective-C++ 的注意事項(xiàng)。內(nèi)存管理是你最應(yīng)該格外注意的點(diǎn),因?yàn)?ARC 只對 Objective-C 對象有效。當(dāng)你使用一個 C++ 對象作為類屬性的時候,其唯一有效的屬性就是 assign。因此,你的 dealloc 函數(shù)應(yīng)確保 C++ 對象被正確地釋放了。

第二重要的點(diǎn)就是,如果你在 Objective-C++ 頭文件中引入了 C++ 頭文件,當(dāng)你在工程中使用該 Objective-C++ 文件的時候就泄露了 C++ 的依賴。任何引入你的 Objective-C++ 類的 Objective-C 類也會引入該 C++ 類,因此該 Objective-C 文件也要被聲明為 Objective-C++ 的文件。這會像森林大火一樣在工程中迅速蔓延。所以,應(yīng)該把你引入 C++ 文件的地方都用 #ifdef __cplusplus 包起來,并且只要可能,就盡量只在 .mm 實(shí)現(xiàn)文件中引入 C++ 頭文件。

要獲得更多如何混用 C++ 和 Objective-C 的細(xì)節(jié),請查看 Matt Galloway 寫的這篇教程。

Demo:人臉檢測與識別

現(xiàn)在,我們對 OpenCV 及如何把它集成到我們的應(yīng)用中有了大概認(rèn)識,那讓我們來做一個小 demo 應(yīng)用:從 iPhone 的攝像頭獲取視頻流,對它持續(xù)進(jìn)行人臉檢測,并在屏幕上標(biāo)出來。當(dāng)用戶點(diǎn)擊一個臉孔時,應(yīng)用會嘗試識別這個人。如果識別結(jié)果正確,用戶必須點(diǎn)擊 “Correct”。如果識別錯誤,用戶必須選擇正確的人名來糾正錯誤。我們的人臉識別器就會從錯誤中學(xué)習(xí),變得越來越好。

http://wiki.jikexueyuan.com/project/objc/images/21-43.jpg" alt="" />

本 demo 應(yīng)用的源碼可從 GitHub 獲得。

視頻拍攝

OpenCV 的 highgui 模塊中有個類,CvVideoCamera,它把 iPhone 的攝像機(jī)抽象出來,讓我們的 app 通過一個代理函數(shù) - (void)processImage:(cv::Mat&)image 來獲得視頻流。CvVideoCamera 實(shí)例可像下面這樣進(jìn)行設(shè)置:

CvVideoCamera *videoCamera = [[CvVideoCamera alloc] initWithParentView:view];
videoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionFront;
videoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPreset640x480;
videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;
videoCamera.defaultFPS = 30;
videoCamera.grayscaleMode = NO;
videoCamera.delegate = self;

攝像頭的幀率被設(shè)置為 30 幀每秒, 我們實(shí)現(xiàn)的 processImage 函數(shù)將每秒被調(diào)用 30 次。因?yàn)槲覀兊?app 要持續(xù)不斷地檢測人臉,所以我們應(yīng)該在這個函數(shù)里實(shí)現(xiàn)人臉的檢測。要注意的是,如果對某一幀進(jìn)行人臉檢測的時間超過 1/30 秒,就會產(chǎn)生掉幀現(xiàn)象。

人臉檢測

其實(shí)你并不需要使用 OpenCV 來做人臉檢測,因?yàn)?Core Image 已經(jīng)提供了 CIDetector 類。用它來做人臉檢測已經(jīng)相當(dāng)好了,并且它已經(jīng)被優(yōu)化過,使用起來也很容易:

CIDetector *faceDetector = [CIDetector detectorOfType:CIDetectorTypeFace context:context options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}];

NSArray *faces = [faceDetector featuresInImage:image];

從該圖片中檢測到的每一張面孔都在數(shù)組 faces 中保存著一個 CIFaceFeature 實(shí)例。這個實(shí)例中保存著這張面孔的所處的位置和寬高,除此之外,眼睛和嘴的位置也是可選的。

另一方面,OpenCV 也提供了一套物體檢測功能,經(jīng)過訓(xùn)練后能夠檢測出任何你需要的物體。該庫為多個場景自帶了可以直接拿來用的檢測參數(shù),如人臉、眼睛、嘴、身體、上半身、下半身和笑臉。檢測引擎由一些非常簡單的檢測器的級聯(lián)組成。這些檢測器被稱為 Haar 特征檢測器,它們各自具有不同的尺度和權(quán)重。在訓(xùn)練階段,決策樹會通過已知的正確和錯誤的圖片進(jìn)行優(yōu)化。關(guān)于訓(xùn)練與檢測過程的詳情可參考此原始論文。當(dāng)正確的特征級聯(lián)及其尺度與權(quán)重通過訓(xùn)練確立以后,這些參數(shù)就可被加載并初始化級聯(lián)分類器了:

// 正面人臉檢測器訓(xùn)練參數(shù)的文件路徑
NSString *faceCascadePath = [[NSBundle mainBundle] pathForResource:@"haarcascade_frontalface_alt2"
                                                   ofType:@"xml"];

const CFIndex CASCADE_NAME_LEN = 2048;
char *CASCADE_NAME = (char *) malloc(CASCADE_NAME_LEN);
CFStringGetFileSystemRepresentation( (CFStringRef)faceCascadePath, CASCADE_NAME, CASCADE_NAME_LEN);

CascadeClassifier faceDetector;
faceDetector.load(CASCADE_NAME);

這些參數(shù)文件可在 OpenCV 發(fā)行包里的 data/haarcascades 文件夾中找到。

在使用所需要的參數(shù)對人臉檢測器進(jìn)行初始化后,就可以用它進(jìn)行人臉檢測了:

cv::Mat img;
vector<cv::Rect> faceRects;
double scalingFactor = 1.1;
int minNeighbors = 2;
int flags = 0;
cv::Size minimumSize(30,30);
faceDetector.detectMultiScale(img, faceRects,
                              scalingFactor, minNeighbors, flags
                              cv::Size(30, 30) );

檢測過程中,已訓(xùn)練好的分類器會用不同的尺度遍歷輸入圖像的每一個像素,以檢測不同大小的人臉。參數(shù) scalingFactor 決定每次遍歷分類器后尺度會變大多少倍。參數(shù) minNeighbors 指定一個符合條件的人臉區(qū)域應(yīng)該有多少個符合條件的鄰居像素才被認(rèn)為是一個可能的人臉區(qū)域;如果一個符合條件的人臉區(qū)域只移動了一個像素就不再觸發(fā)分類器,那么這個區(qū)域非??赡懿⒉皇俏覀兿胍慕Y(jié)果。擁有少于 minNeighbors 個符合條件的鄰居像素的人臉區(qū)域會被拒絕掉。如果 minNeighbors 被設(shè)置為 0,所有可能的人臉區(qū)域都會被返回回來。參數(shù) flags 是 OpenCV 1.x 版本 API 的遺留物,應(yīng)該始終把它設(shè)置為 0。最后,參數(shù) minimumSize 指定我們所尋找的人臉區(qū)域大小的最小值。faceRects 向量中將會包含對 img 進(jìn)行人臉識別獲得的所有人臉區(qū)域。識別的人臉圖像可以通過 cv::Mat() 運(yùn)算符提取出來,調(diào)用方式很簡單:cv::Mat faceImg = img(aFaceRect)。

不管是使用 CIDetector 還是 OpenCV 的 CascadeClassifier,只要我們獲得了至少一個人臉區(qū)域,我們就可以對圖像中的人進(jìn)行識別了。

人臉識別

OpenCV 自帶了三個人臉識別算法:Eigenfaces,F(xiàn)isherfaces 和局部二值模式直方圖 (LBPH)。如果你想知道它們的工作原理及相互之間的區(qū)別,請閱讀 OpenCV 的詳細(xì)文檔。

針對于我們的 demo app,我們將采用 LBPH 算法。因?yàn)樗鼤鶕?jù)用戶的輸入自動更新,而不需要在每添加一個人或糾正一次出錯的判斷的時候都要重新進(jìn)行一次徹底的訓(xùn)練。

要使用 LBPH 識別器,我們也用 Objective-C++ 把它封裝起來。這個封裝中暴露以下函數(shù):

+ (FJFaceRecognizer *)faceRecognizerWithFile:(NSString *)path;
- (NSString *)predict:(UIImage*)img confidence:(double *)confidence;
- (void)updateWithFace:(UIImage *)img name:(NSString *)name;

像下面這樣用工廠方法來創(chuàng)建一個 LBPH 實(shí)例:

+ (FJFaceRecognizer *)faceRecognizerWithFile:(NSString *)path {
    FJFaceRecognizer *fr = [FJFaceRecognizer new];
    fr->_faceClassifier = createLBPHFaceRecognizer();
    fr->_faceClassifier->load(path.UTF8String);
    return fr;
}

預(yù)測函數(shù)可以像下面這樣實(shí)現(xiàn):

- (NSString *)predict:(UIImage*)img confidence:(double *)confidence {
    cv::Mat src = [img cvMatRepresentationGray];
    int label;
    self->_faceClassifier->predict(src, label, *confidence);
    return _labelsArray[label];
}

請注意,我們要使用一個類別方法把 UIImage 轉(zhuǎn)化為 cv::Mat。此轉(zhuǎn)換本身倒是相當(dāng)簡單直接:使用 CGBitmapContextCreate 創(chuàng)建一個指向 cv::Image 中的 data 指針?biāo)赶虻臄?shù)據(jù)的 CGContextRef。當(dāng)我們在此圖形上下文中繪制此 UIImage 的時候,cv::Imagedata 指針?biāo)妇褪撬枰臄?shù)據(jù)。更有趣的是,我們能對一個 Objective-C 類創(chuàng)建一個 Objective-C++ 的類別,并且確實(shí)管用。

另外,OpenCV 的人臉識別器僅支持整數(shù)標(biāo)簽,但是我們想使用人的名字作標(biāo)簽,所以我們得通過一個 NSArray 屬性來對二者實(shí)現(xiàn)簡單的轉(zhuǎn)換。

一旦識別器給了我們一個識別出來的標(biāo)簽,我們把此標(biāo)簽給用戶看,這時候就需要用戶給識別器一個反饋。用戶可以選擇,“是的,識別正確”,也可以選擇,“不,這是 Y,不是 X”。在這兩種情況下,我們都可以通過人臉圖像和正確的標(biāo)簽來更新 LBPH 模型,以提高未來識別的性能。使用用戶的反饋來更新人臉識別器的方式如下:

- (void)updateWithFace:(UIImage *)img name:(NSString *)name {
    cv::Mat src = [img cvMatRepresentationGray];
    NSInteger label = [_labelsArray indexOfObject:name];
    if (label == NSNotFound) {
        [_labelsArray addObject:name];
        label = [_labelsArray indexOfObject:name];
    }
    vector<cv::Mat> images = vector<cv::Mat>();
    images.push_back(src);
    vector<int> labels = vector<int>();
    labels.push_back((int)label);
    self->_faceClassifier->update(images, labels);
}

這里,我們又做了一次了從 UIImagecv::Mat、intNSString 標(biāo)簽的轉(zhuǎn)換。我們還得如 OpenCV 的 FaceRecognizer::update API所期望的那樣,把我們的參數(shù)放到 std::vector 實(shí)例中去。

如此“預(yù)測,獲得反饋,更新循環(huán)”,就是文獻(xiàn)上所說的監(jiān)督式學(xué)習(xí)。

結(jié)論

OpenCV 是一個強(qiáng)大而用途廣泛的庫,覆蓋了很多現(xiàn)如今仍在活躍的研究領(lǐng)域。想在一篇文章中給出詳細(xì)的使用說明只會是讓人徒勞的事情。因此,本文僅意在從較高層次對 OpenCV 庫做一個概述。同時,還試圖就如何集成 OpenCV 庫到你的 iOS 工程中給出一些實(shí)用建議,并通過一個人臉識別的例子來向你展示如何在一個真正的項(xiàng)目中使用 OpenCV。如果你覺得 OpenCV 對你的項(xiàng)目有用, OpenCV 的官方文檔寫得非常好非常詳細(xì),請繼續(xù)前行,創(chuàng)造出下一個偉大的 app!

上一篇:XPC下一篇:Core Data 概述