基於OpenCV和dlib的人臉交換實現探究
計算機視覺對我來說是一個全新的知識領域,希望能夠逐步入門,從影象識別、人臉檢測等問題的研究探討逐步過渡到三維人臉重建技術的研究。在知識空白的情況下,我首先了閱讀一些相關的論文,然後選擇了一個GitHub上的專案,部署環境並參照執行,在落實到程式碼層的同時進一步研究實現過程和原理,希望能夠理解更多的內容。
DO:
1.閱讀《OpenCV入門教程》及dlib官方文件
2.在win10中配置部署OpenCV和dlib
3.在vs2015中執行faceswap專案
4.梳理實現流程,探究演算法
專案地址:
Real-time FaceSwap application built with OpenCV and dlib
初探:
工欲善其事,必先利其器。在軟體不斷的更新迭代的過程中,由於不同版本型號和缺乏經驗,開發環境的正確搭建總是一個有點頭疼的問題。在OpenCV和dlib的開發環境配置的過程中,還是遇到了不少的問題,試遍StackOverflow以及其他社群的各種可能的解決辦法最後終於成功,後來對一些問題的總結記錄在我的另一篇簡書中。——嘗試專案時遇到的問題和解決方案記錄
簡述:
要實現實時換臉,首先要呼叫相機,將相機快取的幀中的人的面部特徵標記出來,這裡用到了dlib提供的特徵點標記方法,定位正臉並返回68個人臉特徵點的位置(landmark)。兩張人臉對應了兩個特徵部分,接下來想辦法實現這兩個特徵部分的輪廓對齊(經過平移旋轉等變換),即實現人臉對齊。之後我們通過仿射變換實現互相交換覆蓋區,再經過顏色矯正和邊緣融合就基本實現了人臉交換。
專案實現細節:
1.呼叫的主要資原始檔:
預設的人臉檢測器:haarcascade_frontalface_default.xml
Dlib68點特徵提取模型:shape_predictor_68_face_landmarks.dat
Dlib與OpenCV其他相關的庫函式
2.類:
FaceDetectorAndTracker類:實現相機捕獲幀中的人臉檢測、跟蹤以及得到相應的人臉矩形。
FaceSwapper類:實現了面部特徵點的提取,求出仿射變換所需座標,實現五官區域提取、面部對齊並求出變換矩陣,利用直方圖法實現了色彩矯正,最後完成邊緣融合完成人臉交換。
3.關鍵步驟解釋:
1).人臉檢測
基於OpenCV的級聯分類器實現目標檢測,利用的是樣本的Haar特徵,級聯分類器的計算特徵值的基礎類FeatureEvaluator,功能包括讀操作read、複製clone、獲得特徵類getFeatureType,分配圖片分配視窗的操作setImage、setWindow,建立分類器特徵的結構create函式。
主要實現過程:載入級聯分類器->讀取視訊流->對每一幀使用該分類器->得到臉部興趣區域的矩形向量。
在檢測人臉時呼叫的一個關鍵函式detectMultiScale如下
//detect()中呼叫
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() );
這個函式的作用是在輸入影象中檢測不同大小的物件。檢測到的物件作為列表返回的矩形。
引數說明:@param image CV_8U型別的矩陣,其中包含檢測物件的影象。
@param objects 每個矩形包含檢測到的物件的矩形向量,矩形可能部分在原始影象之外。
@param scaleFactor引數指定在每個影象比例下影象大小減少了多少。
@param minNeighbors引數指定每個候選矩形應該有多少個要保留的鄰居。
@param flags引數與舊函式中的cvHaarDetectObjects函式具有相同的含義。它不用於新的級聯。
@param minSize最小可能的物件大小。小於這個值的物件被忽略。
@param maxSize最大可能的物件大小。大於此的物件將被忽略。如果`maxSize == minSize`模型是單一尺度評估的。
2).關鍵點定位提取
對攝像頭採集到的每一幀影象快取後進行特徵點檢測並顯示即可。
使用了官方提供的模型構建特徵提取器。
predictor = dlib.shape_predictor(predictor_path)
獲取特徵點座標:
shapes[shape_index].part(part_index).x()/y()
shape_index是人臉的序號,如shapes[0]代表的是第一個人(可以同時檢測到很多個人),part(i)代表的是第i個特徵點,x()和y()是訪問特徵點座標的途徑。
68個點按順序存放了人臉各部位的座標資訊,程式中選取了8,36,45作為仿射變換的關鍵點。(還不太明白原理-_-)
{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] }
3).仿射變換,人臉對齊
參考了面部對齊部分的講解。主要用到了OpenCV提供的函式warpAffine實現了圖片的變換。
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).區域提取
getMasks();
getWarppedMasks();
refined_masks = getRefinedMasks();
extractFaces();
首先計算出變換矩陣M,然後提取特徵部分的mask並把它變換到要覆蓋的位置得到warppedMasks,warppedMasks和它要覆蓋的特徵部分取並以保證完全覆蓋。最後extractFaces實現調整好的mask到對方幀的互相拷貝。
5).色差矯正(color transfer)
色差矯正的目標是使當前人臉與要被替換的人臉色彩相近。專案中採用了直方圖調整的方式:先計算當前影象和目標影象的顏色直方圖,然後調整當前影象與目標影象的一致,最後將調整後的直方圖應用到當前影象。兩張圖互相經過這樣的處理就實現了色差的矯正。
程式中在colorCorrectFaces()函式中呼叫了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() );
使用特定的結構元素侵蝕影象。該函式使用指定的結構元素來侵蝕源影象。(譯自CV文件)
最小取畫素鄰域的形狀:
\f[\texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f]
侵蝕可以應用幾次(迭代)次。在多通道影象的情況下,每個通道都是獨立處理的。
@param src輸入影象;通道的數量可以是任意的,但深度應該是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F其中之一。
@引數dst輸出與src相同大小和型別的影象。
@param kernel 核心結構化元素用於侵蝕;如果`element = Mat()`,一個`3 x 3`矩形結構元素被使用。核心可以使用getStructuringElement建立。
元素內錨的引數錨位置;預設值(-1,-1)表示錨在元素中心。
@param iterations應用erode的次數。
@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 );
使用歸一化的盒子過濾器模糊影象。(引用自官方文件)
該函式使用核心平滑影象:\ 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]
呼叫`blur(src,dst,ksize,anchor,borderType)`相當於`boxFilter(src,dst,src.type(),anchor,true,borderType)`。
@param src輸入影象; 它可以有任意數量的獨立處理的通道,但是
深度應該是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F。
@引數dst輸出與src相同大小和型別的影象。
@引數ksize模糊核心大小。
@引數anchor 預設值Point(-1,-1)表示錨點位於核心處
中央。
@引數 borderType邊界模式,用於外推影象外的畫素,參閱cv :: BorderTypes
@sa Filter,bilateralFilter,GaussianBlur,medianBlur
4.涉及部分函式說明:
在整個實現過程中呼叫了OpenCV和dlib庫中的一些函式實現關鍵大部分演算法。
如
CV_WRAP void detectMultiScale()在輸入影象中檢測不同大小的物件。
CV_EXPORTS_W void matchTemplate()比較模板和重疊的影象區域。
CV_EXPORTS_W void normalize()規範化陣列的範數或值範圍。
CV_EXPORTS_W void minMaxLoc()在陣列中查詢全域性最小值和最大值。
CV_EXPORTS_W void fillConvexPoly()繪製一個填充的凸多邊形。
CV_EXPORTS_W void warpAffine()將仿射變換應用於影象。
CV_EXPORTS_W void blur()使用歸一化的盒子過濾器模糊影象。
CV_EXPORTS_W void erode()使用特定的結構元素侵蝕影象。
關於這些函式的作用和具體的引數介紹我記錄在了我另一篇部落格中FaceSwap函式說明
閱讀文獻及參考連結:
Robust real-time face detection
One millisecond face alignment with an ensemble of regression trees
曹晨.基於單目視訊相機的實時人臉跟蹤與動畫方法研究[D].浙江大學,2016
未來展望:
之前沒怎麼接觸過計算機視覺領域的具體指示,這次reseach對我來說是一個不小的挑戰,發現其中涉及大量的數學知識,線代,統計學,數學分析等等,雖然感到困難重重,但我感覺到巨大的興趣,在看著paper中對三維人臉重建的講解,我眼前展開的是一幅美妙的畫面,大牛們神乎其技各顯神通,複雜的數學公式背後蘊含著深刻又淳樸的哲理和思想。
作為一個剛接觸的這方面的本科生,很多理論基礎都不紮實,在這個專案中的每個環節需要了解的更深,要想透徹的理解演算法,一是要看透演算法原作者的論文, 二是要讀懂相關的優秀原始碼實現,日後我還需要進一步的夯實基礎,向這個方向努力。
另外關於三維人臉重建(3D face reconstruction)的技術,讀了一些論文和當前的成果,感覺超級有意思,對這個領域充滿了好奇和興趣,之後希望能夠在老師和師兄的指導下逐步深入的學習和研究。I'll keep trying and do my best!
相關文章
- 基於OpenCV+dlib開發一個人臉識別應用OpenCV
- 基於opencv實現簡單人臉檢測OpenCV
- 基於celeba資料集和pytorch框架實現dcgan的人臉影像生成PyTorch框架
- 基於卷積神經網路和tensorflow實現的人臉識別卷積神經網路
- 基於PCA和SVM的人臉識別PCA
- [OpenCV實戰]1 基於深度學習識別人臉性別和年齡OpenCV深度學習
- python基於opencv 實現影像時鐘PythonOpenCV
- 基於Python的人臉檢測與分類Python
- 基於二哈實現多人人臉學習和識別
- 基於膚色模型的人臉識別FPGA實現,包含tb測試檔案和MATLAB輔助驗證模型FPGAMatlab
- 基於Python的人臉自動戴口罩系統Python
- 利用opencv 做一個簡單的人臉識別OpenCV
- 基於Android平臺實現人臉識別Android
- 基於Tensorflow + Opencv 實現CNN自定義影像分類OpenCVCNN
- 基於Java實現的人臉識別功能,一切都為了寵粉(附原始碼)Java原始碼
- 基於Flutter實現的 IT換換(已開源)Flutter
- 基於TensorflowLite的人聲識別在端上的實現
- 如何使用DeepFake實現影片換臉
- 實驗十一 ——————二層交換基礎
- 如何用OpenCV在Python中實現人臉檢測OpenCVPython
- 基於DNN的人臉識別中的反欺騙機制DNN
- 解密Deepfake(深度換臉)-基於自編碼器的(Pytorch程式碼)換臉技術解密PyTorch
- 如何用Python實現iPhone X的人臉解鎖功能?PythoniPhone
- 頭部姿態估計 - OpenCV/Dlib/CeresOpenCV
- JavaScript實現兩個數的交換JavaScript
- 如何使用DeepFake實現視訊換臉
- 【ROS】OpenCV+ROS 實現人臉識別(Ubantu16.04)ROSOpenCV
- 【影像處理】基於OpenCV實現影像直方圖的原理OpenCV直方圖
- openCV實戰專案--人臉考勤OpenCV
- OpenCv人臉檢測技術-(實現抖音特效-給人臉戴上墨鏡)OpenCV特效
- python ubuntu dlib人臉識別3-人臉對齊PythonUbuntu
- 帶你玩轉OpenHarmony AI:基於Seetaface2的人臉識別AI
- 基於深度神經網路的人臉識別相關問題神經網路
- dlib 人臉對齊 基本原理
- 圖片人臉檢測——Dlib版(四)
- 視訊人臉檢測——Dlib版(六)
- 基於交換論證的 Johnson 法則證明
- 影片美顏sdk中的人臉磨皮功能實現流程
- 美顏sdk中的人臉美型實現流程詳解