基于OpenCV和dlib的人臉交換實(shí)現(xiàn)探究

計(jì)算機(jī)視覺對(duì)我來說是一個(gè)全新的知識(shí)領(lǐng)域触趴,希望能夠逐步入門,從圖像識(shí)別、人臉檢測(cè)等問題的研究探討逐步過渡到三維人臉重建技術(shù)的研究宏所。在知識(shí)空白的情況下,我首先了閱讀一些相關(guān)的論文摊溶,然后選擇了一個(gè)GitHub上的項(xiàng)目爬骤,部署環(huán)境并參照運(yùn)行,在落實(shí)到代碼層的同時(shí)進(jìn)一步研究實(shí)現(xiàn)過程和原理莫换,希望能夠理解更多的內(nèi)容霞玄。

DO:

1.閱讀《OpenCV入門教程》及dlib官方文檔

2.在win10中配置部署OpenCV和dlib

3.在vs2015中運(yùn)行faceswap項(xiàng)目

4.梳理實(shí)現(xiàn)流程骤铃,探究算法



項(xiàng)目地址:

Real-time FaceSwap application built with OpenCV and dlib


初探:

工欲善其事,必先利其器坷剧。在軟件不斷的更新迭代的過程中惰爬,由于不同版本型號(hào)和缺乏經(jīng)驗(yàn),開發(fā)環(huán)境的正確搭建總是一個(gè)有點(diǎn)頭疼的問題听隐。在OpenCV和dlib的開發(fā)環(huán)境配置的過程中补鼻,還是遇到了不少的問題,試遍StackOverflow以及其他社區(qū)的各種可能的解決辦法最后終于成功雅任,后來對(duì)一些問題的總結(jié)記錄在我的另一篇簡(jiǎn)書中风范。——嘗試項(xiàng)目時(shí)遇到的問題和解決方案記錄


簡(jiǎn)述:

要實(shí)現(xiàn)實(shí)時(shí)換臉沪么,首先要調(diào)用相機(jī)硼婿,將相機(jī)緩存的幀中的人的面部特征標(biāo)記出來,這里用到了dlib提供的特征點(diǎn)標(biāo)記方法禽车,定位正臉并返回68個(gè)人臉特征點(diǎn)的位置(landmark)寇漫。兩張人臉對(duì)應(yīng)了兩個(gè)特征部分,接下來想辦法實(shí)現(xiàn)這兩個(gè)特征部分的輪廓對(duì)齊(經(jīng)過平移旋轉(zhuǎn)等變換)殉摔,即實(shí)現(xiàn)人臉對(duì)齊州胳。之后我們通過仿射變換實(shí)現(xiàn)互相交換覆蓋區(qū),再經(jīng)過顏色矯正和邊緣融合就基本實(shí)現(xiàn)了人臉交換逸月。

項(xiàng)目實(shí)現(xiàn)細(xì)節(jié):


整體框架圖

1.調(diào)用的主要資源文件

默認(rèn)的人臉檢測(cè)器:haarcascade_frontalface_default.xml

Dlib68點(diǎn)特征提取模型:shape_predictor_68_face_landmarks.dat

Dlib與OpenCV其他相關(guān)的庫函數(shù)

2.

FaceDetectorAndTracker類:實(shí)現(xiàn)相機(jī)捕獲幀中的人臉檢測(cè)栓撞、跟蹤以及得到相應(yīng)的人臉矩形。

FaceSwapper類:實(shí)現(xiàn)了面部特征點(diǎn)的提取碗硬,求出仿射變換所需坐標(biāo)瓤湘,實(shí)現(xiàn)五官區(qū)域提取、面部對(duì)齊并求出變換矩陣恩尾,利用直方圖法實(shí)現(xiàn)了色彩矯正弛说,最后完成邊緣融合完成人臉交換。

3.關(guān)鍵步驟解釋:

1).人臉檢測(cè)

基于OpenCV的級(jí)聯(lián)分類器實(shí)現(xiàn)目標(biāo)檢測(cè)翰意,利用的是樣本的Haar特征木人,級(jí)聯(lián)分類器的計(jì)算特征值的基礎(chǔ)類FeatureEvaluator,功能包括讀操作read猎物、復(fù)制clone虎囚、獲得特征類getFeatureType,分配圖片分配窗口的操作setImage蔫磨、setWindow,創(chuàng)建分類器特征的結(jié)構(gòu)create函數(shù)圃伶。

主要實(shí)現(xiàn)過程:加載級(jí)聯(lián)分類器->讀取視頻流->對(duì)每一幀使用該分類器->得到臉部興趣區(qū)域的矩形向量堤如。

在檢測(cè)人臉時(shí)調(diào)用的一個(gè)關(guān)鍵函數(shù)detectMultiScale如下

//detect()中調(diào)用

CV_WRAP void detectMultiScale( InputArray image, CV_OUT std::vector& objects, double scaleFactor = 1.1, int minNeighbors = 3, int flags = 0, Size minSize = Size(), Size maxSize = Size() );

這個(gè)函數(shù)的作用是在輸入圖像中檢測(cè)不同大小的對(duì)象蒲列。檢測(cè)到的對(duì)象作為列表返回的矩形。? ??

參數(shù)說明:@param image CV_8U類型的矩陣搀罢,其中包含檢測(cè)對(duì)象的圖像蝗岖。? ??

@param objects 每個(gè)矩形包含檢測(cè)到的對(duì)象的矩形向量,矩形可能部分在原始圖像之外。

@param scaleFactor參數(shù)指定在每個(gè)圖像比例下圖像大小減少了多少榔至。

@param minNeighbors參數(shù)指定每個(gè)候選矩形應(yīng)該有多少個(gè)要保留的鄰居抵赢。

@param flags參數(shù)與舊函數(shù)中的cvHaarDetectObjects函數(shù)具有相同的含義。它不用于新的級(jí)聯(lián)唧取。

@param minSize最小可能的對(duì)象大小铅鲤。小于這個(gè)值的對(duì)象被忽略。

@param maxSize最大可能的對(duì)象大小枫弟。大于此的對(duì)象將被忽略邢享。如果`maxSize == minSize`模型是單一尺度評(píng)估的。

2).關(guān)鍵點(diǎn)定位提取

對(duì)攝像頭采集到的每一幀圖像緩存后進(jìn)行特征點(diǎn)檢測(cè)并顯示即可淡诗。

使用了官方提供的模型構(gòu)建特征提取器骇塘。

predictor = dlib.shape_predictor(predictor_path)?

獲取特征點(diǎn)坐標(biāo):

shapes[shape_index].part(part_index).x()/y()

shape_index是人臉的序號(hào),如shapes[0]代表的是第一個(gè)人(可以同時(shí)檢測(cè)到很多個(gè)人)韩容,part(i)代表的是第i個(gè)特征點(diǎn)款违,x()和y()是訪問特征點(diǎn)坐標(biāo)的途徑。

68個(gè)點(diǎn)按順序存放了人臉各部位的坐標(biāo)信息群凶,程序中選取了8插爹,36,45作為仿射變換的關(guān)鍵點(diǎn)座掘。(還不太明白原理-_-)

{IdxRange jaw; // [0 , 16]

IdxRange rightBrow; // [17, 21]

IdxRange leftBrow; // [22, 26]

IdxRange nose; //[27, 35]

IdxRange rightEye; // [36, 41]

IdxRange leftEye; // [42, 47]

IdxRange mouth;// [48, 59]

IdxRange mouth2; // [60, 67] }

landmarks 68個(gè)關(guān)鍵點(diǎn)位置圖


3).仿射變換递惋,人臉對(duì)齊

參考了面部對(duì)齊部分的講解。主要用到了OpenCV提供的函數(shù)warpAffine實(shí)現(xiàn)了圖片的變換溢陪。

void FaceSwapper::getTransformationMatrices()? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {? ?trans_ann_to_bob = cv::getAffineTransform(affine_transform_keypoints_ann, affine_transform_keypoints_bob); cv::invertAffineTransform(trans_ann_to_bob, trans_bob_to_ann); }

4).區(qū)域提取

getMasks();? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

getWarppedMasks();? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

refined_masks = getRefinedMasks();? ? ? ? ?

extractFaces();

首先計(jì)算出變換矩陣M萍虽,然后提取特征部分的mask并把它變換到要覆蓋的位置得到warppedMasks,warppedMasks和它要覆蓋的特征部分取并以保證完全覆蓋形真。最后extractFaces實(shí)現(xiàn)調(diào)整好的mask到對(duì)方幀的互相拷貝杉编。

5).色差矯正(color transfer)

色差矯正的目標(biāo)是使當(dāng)前人臉與要被替換的人臉色彩相近。項(xiàng)目中采用了直方圖調(diào)整的方式:先計(jì)算當(dāng)前圖像和目標(biāo)圖像的顏色直方圖咆霜,然后調(diào)整當(dāng)前圖像與目標(biāo)圖像的一致邓馒,最后將調(diào)整后的直方圖應(yīng)用到當(dāng)前圖像。兩張圖互相經(jīng)過這樣的處理就實(shí)現(xiàn)了色差的矯正蛾坯。

程序中在colorCorrectFaces()函數(shù)中調(diào)用了specifyHistogram()完成了該功能光酣。

6).邊緣融合

a).圖像填充/侵蝕cv::erode

CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );

使用特定的結(jié)構(gòu)元素侵蝕圖像。該函數(shù)使用指定的結(jié)構(gòu)元素來侵蝕源圖像脉课。(譯自CV文檔)

最小取像素鄰域的形狀:

\f[\texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f]

侵蝕可以應(yīng)用幾次(迭代)次救军。在多通道圖像的情況下财异,每個(gè)通道都是獨(dú)立處理的。

@param src輸入圖像;通道的數(shù)量可以是任意的唱遭,但深度應(yīng)該是CV_8U戳寸,CV_16U,CV_16S拷泽,CV_32F或CV_64F其中之一疫鹊。

@參數(shù)dst輸出與src相同大小和類型的圖像。

@param kernel 內(nèi)核結(jié)構(gòu)化元素用于侵蝕;如果`element = Mat()`司致,一個(gè)`3 x 3`矩形結(jié)構(gòu)元素被使用拆吆。內(nèi)核可以使用getStructuringElement創(chuàng)建。

元素內(nèi)錨的參數(shù)錨位置;默認(rèn)值(-1蚌吸,-1)表示錨在元素中心锈拨。

@param iterations應(yīng)用erode的次數(shù)。

@param borderType像素外插方法羹唠,參閱cv :: BorderTypes

@param borderValue邊界值

@sa dilate奕枢,morphologyEx,getStructuringElement

b).邊緣模糊處理cv::blur

CV_EXPORTS_W void blur( InputArray src, OutputArray dst, Size ksize, Point anchor = Point(-1,-1), int borderType = BORDER_DEFAULT );

使用歸一化的盒子過濾器模糊圖像佩微。(引用自官方文檔)

該函數(shù)使用內(nèi)核平滑圖像:\ f {1} {\ texttt {ksize.width * ksize.height}} \ begin {bmatrix} 1&1&1& cdots&1&1 \\ 1&1& 1&1 cdots&1&1 \\ \ hdotsfor {6} \\ 1&1&1& cdots&1&1 \\ \ end {bmatrix} \ f]

調(diào)用`blur(src缝彬,dst,ksize哺眯,anchor谷浅,borderType)`相當(dāng)于`boxFilter(src,dst奶卓,src.type()一疯,anchor,true夺姑,borderType)`墩邀。

@param src輸入圖像; 它可以有任意數(shù)量的獨(dú)立處理的通道,但是

深度應(yīng)該是CV_8U盏浙,CV_16U眉睹,CV_16S,CV_32F或CV_64F废膘。

@參數(shù)dst輸出與src相同大小和類型的圖像竹海。

@參數(shù)ksize模糊內(nèi)核大小。

@參數(shù)anchor 默認(rèn)值Point(-1丐黄,-1)表示錨點(diǎn)位于內(nèi)核處

中央斋配。

@參數(shù) borderType邊界模式,用于外推圖像外的像素,參閱cv :: BorderTypes

@sa Filter许起,bilateralFilter十偶,GaussianBlur菩鲜,medianBlur

4.涉及部分函數(shù)說明:

在整個(gè)實(shí)現(xiàn)過程中調(diào)用了OpenCV和dlib庫中的一些函數(shù)實(shí)現(xiàn)關(guān)鍵大部分算法园细。

CV_WRAP void detectMultiScale()在輸入圖像中檢測(cè)不同大小的對(duì)象。

CV_EXPORTS_W void matchTemplate()比較模板和重疊的圖像區(qū)域接校。

CV_EXPORTS_W void normalize()規(guī)范化數(shù)組的范數(shù)或值范圍猛频。

CV_EXPORTS_W void minMaxLoc()在數(shù)組中查找全局最小值和最大值。

CV_EXPORTS_W void fillConvexPoly()繪制一個(gè)填充的凸多邊形蛛勉。

CV_EXPORTS_W void warpAffine()將仿射變換應(yīng)用于圖像鹿寻。

CV_EXPORTS_W void blur()使用歸一化的盒子過濾器模糊圖像。

CV_EXPORTS_W void erode()使用特定的結(jié)構(gòu)元素侵蝕圖像诽凌。

關(guān)于這些函數(shù)的作用和具體的參數(shù)介紹我記錄在了我另一篇博客中FaceSwap函數(shù)說明


閱讀文獻(xiàn)及參考鏈接:

基于仿射變換的多姿態(tài)人臉矯正和識(shí)別

Robust real-time face detection

One millisecond face alignment with an ensemble of regression trees

人臉識(shí)別應(yīng)用之“變臉”

dlib實(shí)現(xiàn)視頻中人臉68特征點(diǎn)提取

變臉

淺析人臉檢測(cè)之Haar分類器方法

曹晨.基于單目視頻相機(jī)的實(shí)時(shí)人臉跟蹤與動(dòng)畫方法研究[D].浙江大學(xué)毡熏,2016


未來展望:

之前沒怎么接觸過計(jì)算機(jī)視覺領(lǐng)域的具體指示,這次reseach對(duì)我來說是一個(gè)不小的挑戰(zhàn)侣诵,發(fā)現(xiàn)其中涉及大量的數(shù)學(xué)知識(shí)痢法,線代,統(tǒng)計(jì)學(xué)杜顺,數(shù)學(xué)分析等等财搁,雖然感到困難重重,但我感覺到巨大的興趣躬络,在看著paper中對(duì)三維人臉重建的講解尖奔,我眼前展開的是一幅美妙的畫面,大牛們神乎其技各顯神通穷当,復(fù)雜的數(shù)學(xué)公式背后蘊(yùn)含著深刻又淳樸的哲理和思想提茁。

作為一個(gè)剛接觸的這方面的本科生,很多理論基礎(chǔ)都不扎實(shí)馁菜,在這個(gè)項(xiàng)目中的每個(gè)環(huán)節(jié)需要了解的更深茴扁,要想透徹的理解算法,一是要看透算法原作者的論文, 二是要讀懂相關(guān)的優(yōu)秀源碼實(shí)現(xiàn)火邓,日后我還需要進(jìn)一步的夯實(shí)基礎(chǔ)丹弱,向這個(gè)方向努力。

另外關(guān)于三維人臉重建(3D face reconstruction)的技術(shù)铲咨,讀了一些論文和當(dāng)前的成果躲胳,感覺超級(jí)有意思,對(duì)這個(gè)領(lǐng)域充滿了好奇和興趣纤勒,之后希望能夠在老師和師兄的指導(dǎo)下逐步深入的學(xué)習(xí)和研究坯苹。I'll? keep trying and do my best!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市摇天,隨后出現(xiàn)的幾起案子粹湃,更是在濱河造成了極大的恐慌恐仑,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件为鳄,死亡現(xiàn)場(chǎng)離奇詭異裳仆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)孤钦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門歧斟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人偏形,你說我怎么就攤上這事静袖。” “怎么了俊扭?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵队橙,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我萨惑,道長(zhǎng)捐康,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任咒钟,我火速辦了婚禮吹由,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘朱嘴。我一直安慰自己倾鲫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布萍嬉。 她就那樣靜靜地躺著乌昔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪壤追。 梳的紋絲不亂的頭發(fā)上磕道,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音行冰,去河邊找鬼溺蕉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛悼做,可吹牛的內(nèi)容都是我干的疯特。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼肛走,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼漓雅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤邻吞,失蹤者是張志新(化名)和其女友劉穎组题,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抱冷,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡崔列,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了徘层。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峻呕。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖趣效,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情猪贪,我是刑警寧澤跷敬,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站热押,受9級(jí)特大地震影響西傀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜桶癣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一拥褂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧牙寞,春花似錦饺鹃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至惹挟,卻和暖如春茄螃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背连锯。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工归苍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人运怖。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓拼弃,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親驳规。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肴敛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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