1. 程式人生 > >人臉識別之一影象採集及人臉庫的建立

人臉識別之一影象採集及人臉庫的建立

人臉識別之第一步,人臉庫的建立。

在官方文件中,提供一個人臉庫的下載,可以下載回來看看人家的是什麼格式的。

我們選擇AT&T人臉庫下載的下載:http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html

AT&T Facedatabase又稱ORL人臉資料庫,40個人,每人10張照片。照片在不同時間、不同光照、不同表情(睜眼閉眼、笑或者不笑)、不同人臉細節(戴眼鏡或者不戴眼鏡)下采集。所有的影象都在一個黑暗均勻的背景下采集的,正面豎直人臉(有些有有輕微旋轉)。

下載回來的是壓縮包,先解壓得到orl_faces資料夾,資料夾下有40個資料夾,命名從“s1”~"s40",每個資料夾放的是同一人的照片,裡面有10張人臉照。

但都是 .pgm 格式的 92 x 112 圖片,在windows下打不開,可在linux下開啟,如下:



看一遍官方提供的人臉庫,大概知道如何存放、處理圖片。後面參考官方方法建立自己的圖片即可。

廢話少說,馬上行動。

一、實現步驟與方法

思路很清晰,如下:

1、開啟攝像頭,採集影象;

2、載入人臉分類器;

3、人臉檢測,並框出人臉部分並顯示影象;

4、在檢測到人臉條件下,一鍵拍照;

5、對人臉部分,調整大小並寫成指定目錄下的影象檔案;

二、實現程式碼

你可自己寫程式碼實現這功能,亦可直接COPY程式碼來用,這只是輔助功能而已。

程式碼如下:

#include "opencv2/objdetect.hpp"
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
#include <stdio.h>

using namespace cv;
using namespace std;

int resize_save(Mat& faceIn, char *path, int FaceSeq);
int get_face(char *path);

int main(int argc, char *argv[])
{
	if(argc != 2)
	{
		printf("usage: %s <path>\n", argv[0]);
		return -1;
	}
	
	get_face(argv[1]);

    return 0;
}

int get_face(char *path)
{
	CascadeClassifier face_cascade;  
	VideoCapture camera;
	char key = 0;
	Mat	frame;
	int ret = 0;
	int faceNum = 1;
	vector<Rect> faces;  
	Mat img_gray;  
	Mat faceImg;

	camera.open(0);		// 開啟攝像頭
	if(!camera.isOpened())
	{
	  cout << "open camera failed. " << endl;
	  return -1;
	}
	cout << "open camera succeed. " << endl;

	// 載入人臉分類器
	ret = face_cascade.load("/root/library/opencv/opencv-3.2.0/data/haarcascades/haarcascade_frontalface_alt2.xml");
	if( !ret )
	{
		printf("load xml failed.\n");
		return -1;
	}
	cout << "load xml succeed. " << endl;

	while (1)  
	{
		camera >> frame;  
		if(frame.empty())
		{
			continue;
		}
		
		cvtColor(frame, img_gray, COLOR_BGR2GRAY);  
		equalizeHist(img_gray, img_gray);  
		
		// 檢測目標
		face_cascade.detectMultiScale(img_gray, faces, 1.1, 3, 0, Size(50, 50)); 

		for(size_t i =0; i<faces.size(); i++)  
		{
			 /* 畫矩形框出目標 */
			rectangle(frame, Point(faces[0].x, faces[0].y), Point(faces[0].x + faces[0].width, faces[0].y + faces[0].height),	
							Scalar(0, 255, 0), 1, 8);	 
		}
		imshow("camera", frame);  // 顯示
		key = waitKey(1);  	// 顯示後要新增延時
		
		switch (key)  
		{
			case 'p':	// 按 P 一鍵拍臉
				// 只限定檢測一個人臉
				if(faces.size() == 1)
				{
					faceImg = frame(faces[0]);
					ret = resize_save(faceImg, path, faceNum);	// 調整大小及儲存
					if(ret == 0)
					{
						printf("resize_save success.\n");
						faceNum ++;
					}
				}
				break;	

			case 27:	// 按 Esc 鍵退出
				cout << "Esc..." << endl;
				return 0;
				
			default:  
				break;	
		}  
	}  
}

int resize_save(Mat& faceIn, char *path, int FaceSeq)
{
	string strName;
	Mat image;
	Mat faceOut;  
	int ret;

	if(faceIn.empty())
	{  
    	printf("faceIn is empty.\n");
      	return -1;  
	}  

	if (faceIn.cols > 100)  
	{  
		resize(faceIn, faceOut, Size(92, 112));		// 調整大小,這裡選擇與官方人臉庫圖片大小相容
		strName = format("%s/%d.jpg", path, FaceSeq);	// 先要建立資料夾
		ret = imwrite(strName, faceOut);  // 檔名字尾要正確 .jpg .bmp ...
		if(ret == false)	// 出現錯誤,請檢測檔名字尾、檔案路徑是否存在
		{
			printf("imwrite failed!\n");
			printf("please check filename[%s] is legal ?!\n", strName.c_str());
			return -1;
		}
		imshow(strName, faceOut);  
	}  
	waitKey(20);  

    return 0;
}

操作說明:

編譯成功後,執行可執行檔案須提供引數,該引數為存放人臉影象的目錄,且須為已有目錄。

按“P”鍵一鍵拍照取臉儲存,按“Esc”鍵退出。

若執行 imwrite() 函式失敗時,請檢查引數目錄是否存在,要儲存的檔名字尾是否合法。

此程式儲存為 .jpg 格式,命名採用編號法由1遞增。

三、執行示例

$ ./get_face abc



四、構建人臉庫

按照以上步驟,可得到單個人的多張人臉照,人臉庫由多個人(>=2)的人臉照組成,如下:


人臉庫須大於或等於2人,這裡暫收集5人照片。

參照官方人臉庫,從“s1”~"s4"命名,每個資料夾放著同一個人的多張人臉照。

能力有限,歡迎指出不足,感激不盡!

人臉識別之第一步,人臉庫的建立。