前言
1、前面博文有演示過如何使用OpenCV自帶的人臉與眼睛的級聯分類器檢測到圖像中的人臉,這里將演示如何打開連接電腦的攝像頭并檢測人臉,然后拍照保存下來,用來做人臉識別的訓練數據。
2.我的編程環境是Windows 7 64位,IDE是VS2015,配置了OpenCV3.3與OpenCV_Contrib,Boost 1.66,其中Boost是用來操作文件和目錄用的,是于如果配置以上的環境,可以看我之前寫的博文。
一、處理官方數據
1.下載OpenCV官方的人臉數據,官方人臉數據總共給了40個人的正臉,分好類放在一個文件目錄下,每個人的人臉數據是10張,格式是pgm的,pgm這個格式是在PC機是無法用看圖軟件打開的,但可以使用OpenCV寫個小程序查看里面的內容。csdn下載地址是:https://download.csdn.net/download/matt45m/11090734 。下載之后打開是這樣的:
每個文件夾下包含10張人臉數據,格式是pgm的,尺寸為92X112。
2.寫個函數查看每個分類的人臉數據,這里使用到boost庫的文件操作類遞歸遍歷每個子目錄下的圖像數據并顯示。
(1)函數代碼
/顯示目標路徑下的所有圖像
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)打開其中的一組數據,可以看到其中的人臉,有各種視角的正臉,這樣我們在錄入要識別的人臉盡量可借鑒官方的視角來收集。
二、收集要識別的人臉數據
收集自己要識別的人臉數據,可以從圖像集里面檢測出人臉,也可以從USB攝像頭或筆記本自帶的攝像頭檢測出人臉,這里給出的代碼是從攝像頭檢測到人臉,然后截取,改成官方給的人臉圖像大小一樣的數據,保存。
1.使用OpenCV人臉檢測的級聯分類器檢測到人臉,如果檢測到當前視頻中只有一張人臉時,然后再用眼睛分類器檢測這張臉是否能完全檢測兩個眼睛,如果能同時檢測到兩個眼睛,按p鍵拍照并保存。保存10張以上的人臉,退出。
void photograph(string save_path,int _cap)
{int image_number = 0;if (!face_detector.load(face_path)){std::cout << "無法打開人臉檢測的級聯分類器!" << endl;exit(0);}if (!eye_detector.load(eye_path)){std::cout << "無法打開左眼檢測的級聯分類器!" << 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);//當檢測到只有一張臉時,檢測眼睛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與官司數據一樣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.我這里跟下載的官方數據保存在一起,文件夾名為41。
3.我多拍了十幾張人臉照片,保存的格式還是跟官方一樣為pgm,然后用showImage()函數去讀取顯示,把太相似的圖像刪除,只保存10張圖像數據就可以了。
三、生成圖像列表文件
當訓練人臉模型的時候,需要讀取人臉和人臉對應的類名(標簽)。官方給的教程是生成csv,本質上是用來讓訓練程序讀取當前數據與對應的標簽,opencv官方教程里面提供了自動生成csv文件的python腳本,文件路徑與文件名是opencv_contrib-3.3.0\modules\face\samples\etc\create_csv.py。復制一份改成自己存放圖像的路徑運行就可以了。但我這里使用Boost庫和C++的讀寫文件,生成了一個faceList.txt也是可以用的。
1.生成faceList.txt的函數代碼:
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 << "當前目錄沒有要訓練的文件!" << std::endl;exit(0);}fs::directory_iterator begin_iter(face_iamge_path);fs::directory_iterator end_iter;int i = 0;//遞歸迭代rescursive 直接定義兩個迭代器:i為迭代起點(有參數),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.調用函數,傳入數據路徑,在當前目錄下生成一個faceList.txt的文件,文件格式如下,標簽名對應目錄類名。
結語
1.到這里所有數據都準備完成,之后就是訓練和識別,影響識別的精準度有很多,訓練數據收集應該是最重要的部分,所以盡量收集各種視角不用光線的正臉。
2.關于整個工程的源碼,運行程序時的bug,或者有如何優化的想法都可以加這個群(487350510)互相討論學習
總結
以上是生活随笔為你收集整理的OpenCV3实现人脸识别(二)——收集要识别的人脸数据集的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。