(三)iOS 上使用 dlib 來(lái)檢測(cè)人臉特征(landmarks)

我們用 dlib 來(lái)做一下人臉特征識(shí)別贱案。

dlib是什么?

官方的自定義是:

lib is a modern C++ toolkit containing machine learning algorithms and tools for creating complex software in C++ to solve real world problems.

它和 opencv 的關(guān)系還蠻緊密的司光,是 opencv 的有效補(bǔ)充。也有專門(mén)的庫(kù)來(lái)處理 opencv 的格式轉(zhuǎn)換什么的侨糟。

iOS 項(xiàng)目導(dǎo)入 dlib

步驟:1.自己編譯靜態(tài)庫(kù) 2.copy 源碼頭文件 3.下載模型

雖然 CocoadPods 有搜索到 pod靠抑,但是不可用界斜。

github 上項(xiàng)目負(fù)責(zé)人也說(shuō)幕帆,不是官方的負(fù)責(zé)的pod娄蔼。所以這里我們采用下載源碼结窘,自己編譯靜態(tài)庫(kù)的方式很洋。

$ cd examples
$ mkdir build
$ cd build
$ cmake -G Xcode .. 
$ cmake --build . --config Release

編譯完之后在 dlib_build 下有一個(gè) dlib.xcodeproj 可以打開(kāi),打靜態(tài)包隧枫。

你需要分別打模擬器和真機(jī)的靜態(tài)庫(kù)喉磁,自己合并。

lipo -create xx1.a xx2.a -output libdlib.a 

然后將 dlib 的源碼 copy 出來(lái)悠垛,即頭文件了线定。

dlib_header.png

然后下載 68 個(gè)點(diǎn)位的人臉特征模型 shape_predictor_68_face_landmarks.dat dlib model file donwload,當(dāng)然你也可以下載5個(gè)點(diǎn)位的模型确买,因?yàn)?8挺大的斤讥,將近100M了。

現(xiàn)在我們有3個(gè)文件了

dlib_folder.png

導(dǎo)入Xcode湾趾,不要將 dlib 這個(gè)文件夾的頭文件導(dǎo)入芭商,否則會(huì)報(bào)錯(cuò)。

Xcode 里填寫(xiě) Header Search PathsLibrary Search Path搀缠,將 dlib 的目錄填進(jìn)去铛楣。比如我的是

$(PROJECT_DIR)/FaceDemo/resources/dlib

Xcode 視角

dlib_xcode.png

另外網(wǎng)上有一些 blog 說(shuō)要導(dǎo)入一些參數(shù),但我測(cè)試不導(dǎo)也沒(méi)問(wèn)題艺普,可能這就是我后面測(cè)試到的性能問(wèn)題簸州。但官方文檔里的預(yù)處理指令和一些 blog 的又不到一致,我也不太確定這里歧譬,但做為 demo岸浑,也就不這么嚴(yán)格了。官方文檔

dlib_Preprocessor.png

頭文件引用

#import <dlib/image_processing.h>
#import <dlib/image_processing/frontal_face_detector.h>
#import <dlib/image_processing/render_face_detections.h>
#import <dlib/opencv.h>

frontal_face_detector.h 是用來(lái)做人臉識(shí)別的瑰步,但我們一般不會(huì)用 dlib 來(lái)做人臉識(shí)別矢洲,所以可以不用導(dǎo)入。

render_face_detections.h 是用來(lái)做人臉特征識(shí)別的

opencv.h 是 dlib 專門(mén)用來(lái)處理 Mat 和 dlib::array2d 數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換的缩焦。

顏色空間

因?yàn)槎际翘幚韴D片有關(guān)读虏,我們會(huì)用到很多像素格式問(wèn)題责静。官方文檔 Image Processing 里講得還是比較清楚的。

如果你使用 RGB盖桥,那么對(duì)應(yīng)灾螃,就應(yīng)該使用 rgb_pixel 和 bgr_pixel 的格式。

opencv 的默認(rèn)格式是 bgr揩徊,所以對(duì)應(yīng)應(yīng)該使用 bgr_pixel睦焕。但如果是 UIImageToMat 轉(zhuǎn)過(guò)來(lái)的,它是帶 alpha通道的靴拱,所以要使用 rgb_alpha_pixel

一個(gè)有趣的點(diǎn)猾普,是 opencv 里默認(rèn)的是 BGR袜炕,但是我們平時(shí)經(jīng)常說(shuō)和用的,都是RGB初家。這就出現(xiàn)了通道順序的問(wèn)題偎窘,如果沒(méi)有注意,可能出現(xiàn)圖片顏色失真的問(wèn)題溜在。找到一篇文章 Satya Mallick: Why does OpenCV use BGR color format ? 解釋大意就是:歷史遺留問(wèn)題陌知。那個(gè)有趣的鐵軌的故事,差不多掖肋∑推希可能當(dāng)時(shí)的廠商們比較通用 BGR,但是現(xiàn)在又比較通用 RGB志笼。雖然如此沿盅,opencv 的庫(kù),還是給出了各種格式之間的轉(zhuǎn)換纫溃,非常貼心易用腰涧。這在使用上應(yīng)該沒(méi)有什么難度,只是需要額外注意這個(gè)問(wèn)題而已紊浩。

dlib_Image_Processing.png

dlib 的人臉識(shí)別

cv::Mat cvImg, bgrImg;
UIImageToMat([UIImage imageNamed:@"face5"], cvImg);
cvtColor(cvImg, bgrImg, cv::COLOR_RGBA2BGR);
    
dlib::frontal_face_detector detector = dlib::get_frontal_face_detector();
    
dlib::array2d<dlib::bgr_pixel> dlibImg;
dlib::assign_image(dlibImg, dlib::cv_image<dlib::bgr_pixel>(bgrImg));
    
std::vector<dlib::rectangle> dets = detector(dlibImg);
NSLog(@"人臉個(gè)數(shù) %lu",dets.size());//檢測(cè)到人臉的數(shù)量

dlib 是不允許 帶 alpha 通道的數(shù)據(jù)處理窖铡。所以我們需要在 OpenCV 轉(zhuǎn)換一下。

要注意的一點(diǎn)坊谁,是 iOS 系統(tǒng)和 OpenCV 的顏色空間通道順序是不同的费彼。

UIImage里是 RGB+Alpha 的形式,但是 OpenCV 的顏色空間順序是 BGR

如果這一步呜袁,你的 Mat 是 灰度圖敌买,那么 <dlib::bgr_pixel>就寫(xiě)成<unsigned char> 來(lái)處理。

總之阶界,不同處理算法的顏色通道順序一定需要注意一下虹钮。

dlib 獲取 landmarks(特征)

特征識(shí)別的速度非沉郑快,并且特別簡(jiǎn)單芙粱。

我們用 dlib::shape_predictor祭玉,它是可以當(dāng)做全局變量使用的,不是一次性的春畔。

NSString *landmarkPath = [[NSBundle mainBundle] pathForResource:@"shape_predictor_68_face_landmarks" ofType:@"dat"];
std::string modelFileString = [landmarkPath UTF8String];

dlib::shape_predictor sp;
dlib::deserialize(modelFileString) >> sp;

將我們之前 OpenCV 優(yōu)化過(guò)的處理加上 dlib

同樣因?yàn)樘幚淼氖腔叶葓D脱货,所以應(yīng)該寫(xiě) <unsigned char> 格式。如果這里律姨,你傳 cv::Mat 是攝像頭的原圖振峻,而不是灰度圖,那么就要用 <dlib::bgr_pixel>择份。

并且涉及到 cv::Rect 和 dlib::rectangle扣孟、cv::Point 和 dlib::point 的單位轉(zhuǎn)換,需要注意一下荣赶。

double scale = 1.0 / 4.0;
cv::Mat orignalImg, gray, smallImg;
UIImageToMat([UIImage imageNamed:@"face1"], orignalImg);
    
// 灰度化凤价、縮小、直方圖增強(qiáng)對(duì)比
cvtColor( orignalImg, gray, cv::COLOR_BGRA2GRAY);
resize( gray, smallImg, smallImg.size(), scale, scale, cv::INTER_LINEAR_EXACT  );
equalizeHist( smallImg, smallImg );
    
std::vector<cv::Rect> faces;
cv::Size minimumSize(0, 0);
faceDetector.detectMultiScale(smallImg, faces, 1.2, 6, 0, minimumSize);
    
dlib::array2d<unsigned char> dlibImage;
dlib::assign_image(dlibImage, dlib::cv_image<unsigned char>(smallImg));
    
cv::Scalar color = cv::Scalar( rand() & 255, rand() & 255, rand() & 255 );
for ( size_t i = 0; i < faces.size(); i++ ) {
    cv::rectangle(orignalImg, cv::Point(faces[i].x / scale, faces[i].y / scale), cv::Point(faces[i].x / scale + faces[i].width / scale, faces[i].y / scale + faces[i].height / scale),
    color);
    
    // dlib Landmarks
    dlib::rectangle det(faces[i].tl().x,faces[i].tl().y, faces[i].br().x, faces[i].br().y);
    dlib::full_object_detection shape = sp(dlibImage, det);
    for (unsigned long k = 0; k < shape.num_parts(); k++) {
        dlib::point p = shape.part(k);
        cv::circle(orignalImg, cv::Point(p.x() / scale, p.y() / scale), 2, color, 2);
    }
}
self.resultView.image = MatToUIImage(orignalImg);

測(cè)試

face1_landmarks.png

應(yīng)用

當(dāng)你擁有了這些特征點(diǎn)之后拔创,就可以做很多事利诺。

比如測(cè)試某幾個(gè)點(diǎn)的比,看是不是皺眉啦剩燥、眨眼啦慢逾。甚至換臉等等操作(我沒(méi)有試過(guò),猜的)灭红。

dlib_point.png

參考

dlib: Miscellaneous Preprocessor Directives

dlib: Image Processing

dlib: model file donwload

Ngxin: Dlib與OpenCV圖片轉(zhuǎn)換

Convert OpenCV's Rect to dlib's rectangle?

會(huì)飛的大馬猴: iOS 相機(jī)流人臉識(shí)別(二)-關(guān)鍵點(diǎn)檢測(cè)(face landmark --Dlib 附demo)

Satya Mallick: Why does OpenCV use BGR color format ?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末氛改,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子比伏,更是在濱河造成了極大的恐慌胜卤,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赁项,死亡現(xiàn)場(chǎng)離奇詭異葛躏,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)悠菜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)舰攒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人悔醋,你說(shuō)我怎么就攤上這事摩窃。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵猾愿,是天一觀的道長(zhǎng)鹦聪。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蒂秘,這世上最難降的妖魔是什么泽本? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮姻僧,結(jié)果婚禮上规丽,老公的妹妹穿的比我還像新娘。我一直安慰自己撇贺,他們只是感情好赌莺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著松嘶,像睡著了一般雄嚣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上喘蟆,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音鼓鲁,去河邊找鬼蕴轨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛骇吭,可吹牛的內(nèi)容都是我干的橙弱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼燥狰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼棘脐!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起龙致,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蛀缝,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后目代,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體屈梁,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年榛了,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了在讶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡霜大,死狀恐怖构哺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情战坤,我是刑警寧澤曙强,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布残拐,位于F島的核電站,受9級(jí)特大地震影響旗扑,放射性物質(zhì)發(fā)生泄漏蹦骑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一臀防、第九天 我趴在偏房一處隱蔽的房頂上張望眠菇。 院中可真熱鬧,春花似錦袱衷、人聲如沸捎废。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)登疗。三九已至,卻和暖如春嫌蚤,著一層夾襖步出監(jiān)牢的瞬間辐益,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工脱吱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留智政,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓箱蝠,卻偏偏與公主長(zhǎng)得像续捂,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宦搬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353