本系列人臉識別文章用的是opencv2,最新版的opencv3.2的代碼請參考文章:
OpenCV之識別自己的臉——C++源碼放送
前段時間對人臉檢測進行了一些嘗試:人臉檢測(C++/Python)但是檢測和識別是不同的,檢測解決的問題是圖片中有沒有人臉;而識別解決的問題是,如果一張圖片中有人臉,這是誰的臉。人臉檢測可以利用opencv自帶的分類器,但是人臉識別就需要自己收集數據,自己訓練分類器了。opencv給出的有人臉識別的教程:Face Recognition with OpenCV。網上也可以找到中文版本的。
正所謂自己動手豐衣足食。站在巨人的肩膀上,參考前輩們的經驗,終于能夠識別出自己了。由于感覺內容較多,而且沒有時間一次性寫完,所以準備分階段來寫。每一篇博客是一個階段的工作。初步設想分為數據收集和預處理、訓練模型和人臉識別三個部分。今天先寫第一部分。
一、背景數據集
本次用的數據集市opencv給出的教程里面的第一個數據集:The AT&T Facedatabase。又稱ORL人臉數據庫,40個人,每人10張照片。照片在不同時間、不同光照、不同表情(睜眼閉眼、笑或者不笑)、不同人臉細節(戴眼鏡或者不戴眼鏡)下采集。所有的圖像都在一個黑暗均勻的背景下采集的,正面豎直人臉(有些有有輕微旋轉)。
下載下來之后是這樣的:
可以看到每個人一個文件夾,每個文件夾下是這個人的十張照片,但是不是我們熟悉的BMP或者是PNG或者是JPEG格式的,而是PGM格式的。windows7自帶的照片查看器和畫圖軟件都不能打開這種格式的圖片。不過好在我昨天剛對imread()函數研究過:使用imread()函數讀取圖片的六種正確姿勢。所以記得opencv文檔里有這樣的描述:
imread()還是很強大的,所以寫個程序看看那這些人是什么樣吧。
二、自己的人臉數據集
1.拍照程序
想要識別自己,單有別人的數據集還是不行的,還需要自己人臉的照片才行。這就需要我們收集自己的照片,然后和上面的那個數據集一起來訓練模型。在拿著手機自拍的過程中我想到,問什么不寫一個程序用電腦的攝像頭自拍呢,隨便還能研究下怎么用opencv實現拍照的功能。經過一番實驗(其實還是費了好長時間),終于寫了一個拍照程序。
程序的功能就是打開電腦攝像頭,當P鍵按下(P是拍照的首字母?還是Photo的首字母?還是Picture的首字母?)的時候,保存當前幀的圖像。簡單到沒朋友(竟然耗費了那么久!)。
while (1)
{
char key = waitKey(100);
cap >> frame;
imshow("frame", frame);
string filename = format("D:\\pic\\pic%d.jpg", i);
switch (key)
{
case'p':
i++;
imwrite(filename, frame);
imshow("photo", frame);
waitKey(500);
destroyWindow("photo");
break;
default:
break;
}
}
然后我們就可以運行程序,不停地按下p鍵對自己一通狂拍了。
2.預處理
在得到自己的人臉照片之后,還需要對這些照片進行一些預處理才能拿去訓練模型。所謂預處理,其實就是檢測并分割出人臉,并改變人臉的大小與下載的數據集中圖片大小一致。
人臉檢測在之前的博客中已經做了介紹,這里就不再贅述。詳情參考:OpenCV人臉檢測(C++/Python)。用ROI分割即可。
檢測出人臉之后改變大小使之與ORL人臉數據庫人臉大小一致。通過加斷點在Locals里面或者是ImageWatch可以看到ORL人臉數據庫人臉的大小是92 x 112。
這里只需要對檢測后得到的ROI做一次resize即可。
這兩步的代碼如下:
std::vector<Rect> faces;
Mat img_gray;
cvtColor(img, img_gray, COLOR_BGR2GRAY);
equalizeHist(img_gray, img_gray);
//-- Detect faces
face_cascade.detectMultiScale(img_gray, faces, 1.1, 3, CV_HAAR_DO_ROUGH_SEARCH, Size(50, 50));
for (size_t j = 0; j < faces.size(); j++)
{
Mat faceROI = img(faces[j]);
Mat MyFace;
if (faceROI.cols > 100)
{
resize(faceROI, MyFace, Size(92, 112));
string str = format("D:\\MyFaces\\MyFcae%d.jpg", i);
imwrite(str, MyFace);
imshow("ii", MyFace);
}
waitKey(10);
}
至此,我們就得到和ORL人臉數據庫人臉大小一致的自己的人臉數據集。然后我們把自己的作為第41個人,在我們下載的人臉文件夾下建立一個s41的子文件夾,把自己的人臉數據放進去。就成了這樣下面這樣,最后一個文件夾里面是我自己的頭像照片:
最后那個at.txt放到下一次再說,訓練模型就靠它了。
這里有一點值得注意:我這里保存的圖像格式是.jpg的,而不是跟原數據集一樣是.pgm的。經測試仍然可以訓練出可以正確識別我自己人臉的模型來。但是如果大小不一致會報錯。
之后的內容放到下一次記錄。未完待續......
公眾號CVPy,分享OpenCV和Python的實戰內容。每一篇都會放出完整的代碼。歡迎關注。