今天同學讓我幫忙制作一個人臉表情識別的樣本庫,當中主要是對人臉進行裁剪,這里用到了一個相對較新的Matlab人臉檢測方法Face Parts Detection。網上百度了一下發現關於Matlab人臉檢測的代碼和資源並不多。故此專門撰寫一篇博客來具體介紹這個人臉檢測方法的用途。
一、下載相應的工具包
首先下載相應的工具包。matlab最方便的地方莫過於此了。直接下載、配置簡單、而且能夠查看源代碼,這里給出相應的工具包下載地址:Face Parts Detection工具包。
點擊“Download Zip”下載button開始下載,下載完畢后解壓,得到例如以下文件:
二、配置工具包
下載完畢后開始配置工具箱。首先須要強調一點,這種方法須要依賴兩個Matlab圖像處理方面的工具箱Image Processing Toolbox和Computer Vision System Toolbox。差點兒全部版本號的Matlab都默認集成了Image Processing工具箱。但對於Computer Vision System工具箱僅僅有相對較高版本號(Matlab2013及以上)的Matlab版本號才進行了集成,因此假設在程序運行過程中提示缺少相應的工具箱,則須要手動進行配置Computer Vision System。
假設Matlab已經配置好了以上兩個工具箱,接下來開始配置Face Parts Detection工具包,方法極其簡單,僅僅需在Set Path對話框中將當前工具箱的目錄(這里是Face_detection_Parts目錄)路徑加入到系統的搜索路徑就可以:
三、進行批量人臉檢測
工具箱配置完畢后開始利用其進行人臉檢測。
3.1、批量讀取圖片
首先,須要對數據庫中的圖像進行批量讀取,讀取完之后再進行人臉檢測。首先給出批量讀取的代碼。稍后解釋:
clear; stImageFilePath = 'E:\CAS-PEAL-R1(1)\CAS-PEAL-R1\FRONTAL\Expression\'; stImageSavePath = 'E:\Face_Detection\'; dirImagePathList = dir(strcat(stImageFilePath,'*.tif')); %讀取該目錄下全部圖片的路徑(字符串格式) iImageNum = length(dirImagePathList); %獲取圖片的總數量 if iImageNum > 0 %批量讀入圖片,進行五官檢測,再批量檢測 for i = 1 : iImageNum iSaveNum = int2str(i); stImagePath = dirImagePathList(i).name; mImageCurrent = imread(strcat(stImageFilePath,stImagePath)); end end
這里採用dir()函數的方法來讀取目錄下全部文件的文件名稱,dirImagePathList(i).name中保存了目錄下的全部文件的名稱。
有關Matlab中dir()函數的使用方法大家能夠參考網絡資料。
stImageFilePath變量保存了當前圖片所在目錄的路徑(這里為E:\CAS-PEAL-R1(1)\CAS-PEAL-R1\FRONTAL\Expression\),stImageSavePath變量指定了裁剪之后的人臉圖像的保存路徑。
這里須要注意的一點就是保存裁剪結果的目錄須要事先創建好(或者在程序中通過mkdir等函數來提前創建)。通過strcat()函數來推斷當前圖像名稱中是否包括“.tif”來確定其是否為圖像文件(這里的數據庫中的圖像文件都是tif格式的),
3.2、編寫人臉檢測函數
批量讀取圖像完畢后。開始進行人臉檢測,這里選擇將人臉檢測封裝為一個腳本文件方便調用。這里暫且將其命名為face_segment.m文件。
首先,須要推斷當前圖像的通道數,由於Face Parts Detection方法僅僅能針對三通道圖像進行人臉檢測,假設當前圖像為灰度圖(單通道圖)。則須要先將其轉換為三通道矩陣形式:
%%%%%%%%%%%%%%%%%%%%將灰度圖變為三通道圖%%%%%%%%%%%%%%%%%%%% if(size(mImageSrc,3) == 1) mImage2detect(:,:,1) = mImageSrc; mImage2detect(:,:,2) = mImageSrc; mImage2detect(:,:,3) = mImageSrc; else mImage2detect = mImageSrc; end
然后開始調用工具箱進行人臉檢測。就兩句代碼就可以(可見作者將程序封裝得何其之好):
%%%%%%%%%%%%%%%%%%%%對圖像進行人臉檢測%%%%%%%%%%%%%%%%%%%% FaceDetector = buildDetector(); [bbox,bbimg,faces,bbfaces] = detectFaceParts(FaceDetector,mImage2detect,2);
對於bbox,bbimg,faces,bbfaces這四個檢測結果的具體含義,在detectFaceParts.m文件的開頭部分作者給出了具體的解釋,我們這里僅僅用到bbox這個變量。它里面分別保存了所檢測出的人臉區域(一個矩形框)的左上角坐標以及寬度和高度。
檢測完畢之后。再統一將圖像轉換為灰度圖,保證格式的統一。方便保存:
%%%%%%%%%%%%%%%%%%%%輸入圖像灰度化%%%%%%%%%%%%%%%%%%%% if 1 ~= size(mImageSrc,3) mImageSrc = rgb2gray(mImageSrc); mImageSrc = double(mImageSrc); elseif 1 == size(mImageSrc,3) mImageSrc = double(mImageSrc); end
接下來開始對人臉區域進行切割。這個有兩種切割策略,一種是直接使用檢測到的人臉框bbox對原圖進行截取,在不可控的採集條件下僅僅能用這樣的方法來切割人臉。另外一種策略是針對人臉框bbox首先確定人臉區域的中心點,然后再以中心點為基准向四周依照一定比例進行外擴,這樣的方法僅適合採集條件嚴格可控、人臉大致對齊的人臉數據庫,恰好我們所處理的數據庫滿足這樣的要求。因此在這里採用另外一種策略進行人臉區域切割,代碼例如以下:
%%%%%%%%%%%%%%%%%%%%得到人臉區域框的中心點%%%%%%%%%%%%%%%%%%%% recFace.x = bbox(1,1); recFace.y = bbox(1,2); recFace.width = bbox(1,3); recFace.height = bbox(1,4); ptFaceCenter.x = recFace.x + recFace.width / 2; ptFaceCenter.y = recFace.y + recFace.height / 2; %%%%%%%%%%%%%%%%%%%%以中心點為基准進行外擴(即對人臉選框進行調整)%%%%%%%%%%%%%%%%%%%% recFace.x = ptFaceCenter.x - recFace.width * 0.4; recFace.y = ptFaceCenter.y - recFace.height * 0.35; recFace.width = recFace.width * 0.8 ; recFace.height = recFace.height * 0.8 ; mFaceResult = uint8(imcrop(mImageSrc,[recFace.x,recFace.y,recFace.width,recFace.height]));
這里僅僅涉及到了簡單的幾何知識,因此不再贅述。確定好人臉矩形區域之后,使用imcrop()函數進行區域切割。這里給出face_segment.m文件的完整代碼:
%=============================================================================== %函數名稱:face_segment %輸入參數:mImageSrc,待切割的人臉圖像。可能是灰度圖像,也可能是彩色圖像 %輸出參數:mFaceResult,切割后的人臉結果,應為灰度圖像 %主要步驟:1)進行人臉檢測,得到臉部區域的框框 % 2)得到臉部圖像框的中心點 % 3)依據中心點。對圖像進行等比例外擴,得到合適大小的人臉圖像 %注意事項:1)首先須要推斷該圖像是否為灰度圖。若為灰度圖,須要先將其轉換為三通道彩色圖 %=============================================================================== function mFaceResult = face_segment(mImageSrc) %%%%%%%%%%%%%%%%%%%%將灰度圖變為三通道圖%%%%%%%%%%%%%%%%%%%% if(size(mImageSrc,3) == 1) mImage2detect(:,:,1) = mImageSrc; mImage2detect(:,:,2) = mImageSrc; mImage2detect(:,:,3) = mImageSrc; else mImage2detect = mImageSrc; end %%%%%%%%%%%%%%%%%%%%對圖像進行人臉檢測%%%%%%%%%%%%%%%%%%%% FaceDetector = buildDetector(); [bbox,bbimg,faces,bbfaces] = detectFaceParts(FaceDetector,mImage2detect,2); %%%%%%%%%%%%%%%%%%%%輸入圖像灰度化%%%%%%%%%%%%%%%%%%%% if 1 ~= size(mImageSrc,3) mImageSrc = rgb2gray(mImageSrc); mImageSrc = double(mImageSrc); elseif 1 == size(mImageSrc,3) mImageSrc = double(mImageSrc); end %%%%%%%%%%%%%%%%%%%%得到人臉區域框的中心點%%%%%%%%%%%%%%%%%%%% recFace.x = bbox(1,1); recFace.y = bbox(1,2); recFace.width = bbox(1,3); recFace.height = bbox(1,4); ptFaceCenter.x = recFace.x + recFace.width / 2; ptFaceCenter.y = recFace.y + recFace.height / 2; %%%%%%%%%%%%%%%%%%%%以中心點為基准進行外擴(即對人臉選框進行調整)%%%%%%%%%%%%%%%%%%%% recFace.x = ptFaceCenter.x - recFace.width * 0.4; recFace.y = ptFaceCenter.y - recFace.height * 0.35; recFace.width = recFace.width * 0.8 ; recFace.height = recFace.height * 0.8 ; mFaceResult = uint8(imcrop(mImageSrc,[recFace.x,recFace.y,recFace.width,recFace.height])); end
四、人臉批量保存
在完畢人臉檢測函數之后,開始對人臉進行檢測切割和批量保存,這里直接給出代碼:
clear; stImageFilePath = 'E:\CAS-PEAL-R1(1)\CAS-PEAL-R1\FRONTAL\Expression\'; stImageSavePath = 'E:\Face_Detection\'; dirImagePathList = dir(strcat(stImageFilePath,'*.tif')); %讀取該目錄下全部圖片的路徑(字符串格式) iImageNum = length(dirImagePathList); %獲取圖片的總數量 if iImageNum > 0 %批量讀入圖片,進行五官檢測,再批量檢測 for i = 1 : iImageNum iSaveNum = int2str(i); stImagePath = dirImagePathList(i).name; mImageCurrent = imread(strcat(stImageFilePath,stImagePath)); mFaceResult = face_segment(mImageCurrent); imwrite(mFaceResult,strcat(stImageSavePath,iSaveNum,'.bmp')); end end
這段代碼的邏輯相對簡單。調用strcat()字符串拼接函數來完畢檢測結果的自己主動命名,考慮到版權問題,這里不粘貼終於的人臉切割結果,但程序親測可用,沒有問題。
五、注意事項
1、OpenCv人臉檢測函數
進行人臉檢測是Matlab並非唯一選擇,OpenCv也相同封裝的人臉檢測函數,只是OpenCv中封裝的人臉檢測函數是基於AdaBoost算法。相對經典而古老。性能不如本文中所介紹的人臉檢測算法,而且OpenCv在讀取tif格式的圖像文件時顯得異常麻煩。
2、原理介紹
在這篇博文中我們僅僅介紹了Face Parts Detection算法的具體使用方法,至於去人臉檢測原理,將來有時間了我再專門寫博文進行介紹。
3、打不開MathWork官網的話我能夠給發郵箱
假設出現不能正常登陸MathWork站點,無法下載工具箱的情況。能夠給我發郵件,我會抓時間提供相應的工具箱
4、灰度圖不等於單通道圖
在這里再強調一個小問題。就是灰度圖與單通道圖的關系,理論上來說這兩個名詞全然屬於不同的概念。灰度圖不一定是單通道圖。由於三個通道的RGB值均相等的三通道圖在視覺上相同變現為灰度圖。只是單通道圖肯定是灰度圖。