前言
1、前面博文有演示過如何使用OpenCV自帶的人臉與眼睛的級聯(lián)分類器檢測到圖像中的人臉,這里將演示如何打開連接電腦的攝像頭并檢測人臉,然后拍照保存下來,用來做人臉識別的訓(xùn)練數(shù)據(jù)。
2.我的編程環(huán)境是Windows 7 64位,IDE是VS2015,配置了OpenCV3.3與OpenCV_Contrib,Boost 1.66,其中Boost是用來操作文件和目錄用的,是于如果配置以上的環(huán)境,可以看我之前寫的博文。
一、處理官方數(shù)據(jù)
1.下載OpenCV官方的人臉數(shù)據(jù),官方人臉數(shù)據(jù)總共給了40個人的正臉,分好類放在一個文件目錄下,每個人的人臉數(shù)據(jù)是10張,格式是pgm的,pgm這個格式是在PC機是無法用看圖軟件打開的,但可以使用OpenCV寫個小程序查看里面的內(nèi)容。csdn下載地址是:https://download.csdn.net/download/matt45m/11090734 。下載之后打開是這樣的:
每個文件夾下包含10張人臉數(shù)據(jù),格式是pgm的,尺寸為92X112。
2.寫個函數(shù)查看每個分類的人臉數(shù)據(jù),這里使用到boost庫的文件操作類遞歸遍歷每個子目錄下的圖像數(shù)據(jù)并顯示。
(1)函數(shù)代碼
/顯示目標(biāo)路徑下的所有圖像
void showImage(string image_path)
{//判斷是事為文件夾if (!fs::is_directory(image_path)){Mat image = imread(image_path);if (!image.empty()){imshow(image_path, image);waitKey(0);}}else if(fs::is_directory(image_path)){fs::recursive_directory_iterator begin_iter(image_path);fs::recursive_directory_iterator end_iter;for (; begin_iter != end_iter; begin_iter++){string file_name = begin_iter->path().string();if (!fs::is_directory(file_name)){Mat image = imread(file_name);if (!image.empty()){imshow(file_name, image);waitKey(30);}}}}
}
(2)打開其中的一組數(shù)據(jù),可以看到其中的人臉,有各種視角的正臉,這樣我們在錄入要識別的人臉盡量可借鑒官方的視角來收集。
二、收集要識別的人臉數(shù)據(jù)
收集自己要識別的人臉數(shù)據(jù),可以從圖像集里面檢測出人臉,也可以從USB攝像頭或筆記本自帶的攝像頭檢測出人臉,這里給出的代碼是從攝像頭檢測到人臉,然后截取,改成官方給的人臉圖像大小一樣的數(shù)據(jù),保存。
1.使用OpenCV人臉檢測的級聯(lián)分類器檢測到人臉,如果檢測到當(dāng)前視頻中只有一張人臉時,然后再用眼睛分類器檢測這張臉是否能完全檢測兩個眼睛,如果能同時檢測到兩個眼睛,按p鍵拍照并保存。保存10張以上的人臉,退出。
void photograph(string save_path,int _cap)
{int image_number = 0;if (!face_detector.load(face_path)){std::cout << "無法打開人臉檢測的級聯(lián)分類器!" << endl;exit(0);}if (!eye_detector.load(eye_path)){std::cout << "無法打開左眼檢測的級聯(lián)分類器!" << endl;exit(0);}cap.open(_cap);if (!cap.isOpened()){std::cout << "無法打開攝像頭!" << std::endl;exit(0);}Mat frame;Mat gray;Mat use_face;vector<Rect> faces;vector<Rect> eyes;while (cap.read(frame)){cvtColor(frame, gray, COLOR_BGR2GRAY);equalizeHist(gray, gray);//flip(gray, gray, 1);vector<Rect> faces;face_detector.detectMultiScale(gray, faces, 1.2, 3, 0, Size(30, 30));for (size_t t = 0; t < faces.size(); t++){Rect roi;roi.x = faces[static_cast<int>(t)].x;roi.y = faces[static_cast<int>(t)].y;roi.width = faces[static_cast<int>(t)].width;roi.height = faces[static_cast<int>(t)].height / 2;Mat faceROI = frame(roi);//當(dāng)檢測到只有一張臉時,檢測眼睛if (faces.size() == 1){eye_detector.detectMultiScale(faceROI, eyes, 1.2, 3, 0, Size(20, 20));for (size_t k = 0; k < eyes.size(); k++){Rect rect;rect.x = faces[static_cast<int>(t)].x + eyes[k].x;rect.y = faces[static_cast<int>(t)].y + eyes[k].y;rect.width = eyes[k].width;rect.height = eyes[k].height;rectangle(frame, rect, Scalar(0, 0, 255), 2, 8, 0);//只有都檢測到兩只眼睛時開始拍照if (eyes.size() == 2){char key = waitKey(100);switch (key){//按下p鍵時開始拍照case'p':{Mat face_roi = gray(faces[0]);//圖像序號加1image_number++;//將檢測到的人臉大小改為92*112與官司數(shù)據(jù)一樣resize(face_roi, use_face, Size(92, 112));string filename = save_path + format("%d.jpg", image_number);//存放到傳入的目錄imwrite(filename, use_face);imshow(filename, use_face);waitKey(1000);//銷毀指定的窗口destroyWindow(filename);break;}}//按ese鍵退出拍照if (key == 27){cap.release();exit(0);}}}rectangle(frame, faces[t], Scalar(255, 0, 0), 2, 8, 0);}}imshow("camera", frame);waitKey(33);}
}
2.我這里跟下載的官方數(shù)據(jù)保存在一起,文件夾名為41。
3.我多拍了十幾張人臉照片,保存的格式還是跟官方一樣為pgm,然后用showImage()函數(shù)去讀取顯示,把太相似的圖像刪除,只保存10張圖像數(shù)據(jù)就可以了。
三、生成圖像列表文件
當(dāng)訓(xùn)練人臉模型的時候,需要讀取人臉和人臉對應(yīng)的類名(標(biāo)簽)。官方給的教程是生成csv,本質(zhì)上是用來讓訓(xùn)練程序讀取當(dāng)前數(shù)據(jù)與對應(yīng)的標(biāo)簽,opencv官方教程里面提供了自動生成csv文件的python腳本,文件路徑與文件名是opencv_contrib-3.3.0\modules\face\samples\etc\create_csv.py。復(fù)制一份改成自己存放圖像的路徑運行就可以了。但我這里使用Boost庫和C++的讀寫文件,生成了一個faceList.txt也是可以用的。
1.生成faceList.txt的函數(shù)代碼:
void buildList(string face_iamge_path)
{string bow_path = face_iamge_path + string("faceList.txt");ifstream read_file(bow_path);ofstream ous(bow_path);fs::path face_path(face_iamge_path);if (!fs::exists(face_path)){std::cout << "當(dāng)前目錄沒有要訓(xùn)練的文件!" << std::endl;exit(0);}fs::directory_iterator begin_iter(face_iamge_path);fs::directory_iterator end_iter;int i = 0;//遞歸迭代rescursive 直接定義兩個迭代器:i為迭代起點(有參數(shù)),end_iter迭代終點for (; begin_iter != end_iter; ++begin_iter){i++;if (fs::is_directory(begin_iter->path())){fs::directory_iterator begin(begin_iter->path());fs::directory_iterator end;for (; begin != end; ++begin){string face_name = begin->path().string() + ";" + to_string(i);//cout << face_name << endl;ous << face_name << endl;}}}ous.close();
}
2.調(diào)用函數(shù),傳入數(shù)據(jù)路徑,在當(dāng)前目錄下生成一個faceList.txt的文件,文件格式如下,標(biāo)簽名對應(yīng)目錄類名。
結(jié)語
1.到這里所有數(shù)據(jù)都準(zhǔn)備完成,之后就是訓(xùn)練和識別,影響識別的精準(zhǔn)度有很多,訓(xùn)練數(shù)據(jù)收集應(yīng)該是最重要的部分,所以盡量收集各種視角不用光線的正臉。
2.關(guān)于整個工程的源碼,運行程序時的bug,或者有如何優(yōu)化的想法都可以加這個群(487350510)互相討論學(xué)習(xí)
總結(jié)
以上是生活随笔為你收集整理的OpenCV3实现人脸识别(二)——收集要识别的人脸数据集的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。