天天看點

OpenCV人臉檢測與人臉識别

OpenCV人臉檢測與人臉識别

tkorays(http://blog.csdn.net/tkorays)

成為領袖,而不是依賴别人的指揮。

        用OpenCV做人臉檢測與人臉識别是一件比較簡單的事情,因為OpenCV的庫已經為我們做了很多工作,我們甚至不需要太了解原理,調用就行了。

        注意,人臉檢測(Detection)和人臉識别(Recognition)不是同一個概念。所謂“檢測”是将一張圖檔或視訊的一幀裡的人臉找出來,隻是找出,并不需要知道他(她)是誰。而人臉“識别”,重在識别出人臉是誰。是以,人臉識别過程中常常是先找出人臉,再去判斷人臉屬于誰的。

        這篇部落格我們使我們的代碼盡量簡化,能使讀者一看就會。接下來,我們就一步步來介紹吧。

人臉檢測

準備素材

        首先,我們準備好素材,找一些包含人臉的圖檔,這裡我們随便拍幾張就可以了。

        當然有很多人臉庫可以利用,CSDN上有篇Blog介紹了一些人臉庫,可以直接下載下傳用:http://blog.csdn.net/onlyyouandme/article/details/5596915。

檢測原理

        這裡我們使用OpenCV的級聯(Cascade)分類器來做人臉檢測。所謂級聯分類器,即将多個弱分類器組合起來得到一個性能比較好的分類器。如果你學過機器學習,那麼你對這個肯定不會陌生。

        既然是分類器,首先肯定是要學習的,這裡我們不需要做這一步的,因為OpenCV已經為我們訓練好了人臉的分類器,我們要做的是加載這個級聯分類器分類器檔案。當然,級聯分類器不止是做人臉檢測的,你還可以使用它來檢測其他物體,詳情可以參考OpenCV官方教程“級聯分類器訓練”:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/user_guide/ug_traincascade.html。

        主要使用的是CascadeClassifier這個類,以及load、detectMultiScale函數。

        首先加載已經訓練好的分類器,參數儲存在一個檔案裡,如OpenCV提供的用于人臉檢測的分類器檔案haarcascade_frontalface_default.xml等,這些檔案可以在OpenCV安裝檔案的data目錄裡面找到。

        然後傳入圖檔檢測,得到檢測結果(包含人臉的一個矩形區域)。

代碼參考

/*
 * 一個最簡單的人臉檢測實作
 * @author tkorays<[email protected]>
 */

// 靜态連接配接庫包含
// 可以從 http://github.com/tkorays/cxxlib 擷取
#include "../cxxlib/cv_lib.h" 
#pragma comment(lib, cvLIB("core"))
#pragma comment(lib, cvLIB("highgui"))
#pragma comment(lib, cvLIB("imgproc"))
#pragma comment(lib, cvLIB("objdetect"))
// -----------------------------------------

#include <string>
#include <iostream>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\objdetect\objdetect.hpp>
using namespace std;
using namespace cv;

#define FACE_CASCADE_FILE "E:/haarcascade_frontalface_default.xml"
#define FACE_IMG_FILE "E:/1.jpg"

int main() {
	Mat img = imread(FACE_IMG_FILE,CV_LOAD_IMAGE_GRAYSCALE); // 讀取為灰階圖檔
	vector<Rect> result;
	CascadeClassifier face_detection;
	face_detection.load(FACE_CASCADE_FILE); // 加載級聯分類器
	// 檢測人臉,參數說明:
	// (原始圖檔,結果,尺度因子,最小鄰居數,檢測方法,最小檢測視窗大小)
	face_detection.detectMultiScale(img, result, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, cv::Size(30, 30));
	// 看檢測出人臉的個數,人臉在圖檔中位置儲存在vector的每個Rect中
	cout << "檢測出人臉數: " << result.size() << endl;
	return 0;
}
           

人臉識别

準備素材

        人臉識别要準備的素材要稍微多點了,因為這裡面我們要對分類器進行訓練了。OpenCV并沒有提供識别張三和李四人臉的分類器資料,我們需要自己對分類器訓練,讓它對不同人臉進行分類。

        這裡我們隻識别兩個人,不妨每個人臉提供5張照片吧,要提高識别精度你可以多提供一些照片,但是訓練時間也就變長了。

        人臉圖檔要求同樣大小,隻包括人臉部分,不包括其他部分。這個你可以使用OpenCV來做,也可以用一些截圖工具(記住要同樣大小的)。

OpenCV人臉檢測與人臉識别

圖1 人臉

識别原理

        原理,這裡面沒有什麼可以多說的,如果真的要說會說很多。

       我們用到的主要就是FaceRecognizer這個類,這個類沒有構造函數,必須通過函數調用來初始化。用于初始化的有三個函數:

OpenCV人臉檢測與人臉識别

圖2 人臉識别函數

        Create[Eigen|Fisher|LBPH]FaceRecognizer,三個函數對應着三種識别方法,如果你了解模式識别之類的東西,那你肯定知道他們是什麼,如果不了解也沒關系,除非你要深入研究,否則這裡會用就可以了。

        然後就是訓練與識别了,詳細資訊見代碼。

代碼參考

/*
* 一個最簡單的人臉識别實作
* @author tkorays<[email protected]>
*/

// 靜态連接配接庫包含
// 可以從 http://github.com/tkorays/cxxlib 擷取
#include "../cxxlib/cv_lib.h" 
#pragma comment(lib, cvLIB("core"))
#pragma comment(lib, cvLIB("contrib"))
#pragma comment(lib, cvLIB("highgui"))
#pragma comment(lib, cvLIB("imgproc"))
#pragma comment(lib, cvLIB("objdetect"))
// -----------------------------------------

#include <string>
#include <iostream>
#include <sstream>
#include <opencv2\core\core.hpp>
#include <opencv2\contrib\contrib.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\objdetect\objdetect.hpp>
using namespace std;
using namespace cv;
string FACE_FILE_PATH = "E:/BigData/face_data/";

int main() {
	// 準備資料
	vector<Mat> faces;
	vector<int> labels;
	stringstream ss;
	string s_index;
	// 讀取兩個人的人臉資料
	// 特征臉以及fisher方法要求為灰階
	for (size_t i = 0; i < 5; i++) {
		ss << i;
		ss >> s_index;
		faces.push_back(imread(FACE_FILE_PATH + "PEOPLE_1/small/" + s_index + ".jpg",CV_LOAD_IMAGE_GRAYSCALE));
		labels.push_back(1);
	}
	for (size_t i = 0; i < 5; i++) {
		ss << i;
		ss >> s_index;
		faces.push_back(imread(FACE_FILE_PATH + "PEOPLE_2/small/" + s_index + ".jpg", CV_LOAD_IMAGE_GRAYSCALE));
		labels.push_back(2);
	}
	// --------------------------------------------------------------------------
	// 訓練
	// 建立人臉識别類,這裡可以選擇特征臉,fisher,以及LBPH這三種方法
	// createEigenFaceRecognizer,createFisherFaceRecognizer,createLBPHFaceRecognizer
	Ptr<FaceRecognizer> face_recog = createEigenFaceRecognizer(20);
	face_recog->train(faces, labels); // 傳入人臉圖檔以及标簽
	int face_id = face_recog->predict(imread(FACE_FILE_PATH + "PEOPLE_1/small/" + "6.jpg", CV_LOAD_IMAGE_GRAYSCALE));
	// 識别
	cout << face_id << endl;

	return 0;
}
           

         注意,這裡我們訓練完後可以将訓練好的一些參數儲存起來(FaceRecognizer::save),以便下次使用不要再加載圖檔訓練,而是像上面的級聯分類器一樣直接加載xml檔案就可以工作了。

建議

        有不會用的函數不妨去OpenCV論壇的文檔上去搜尋,本部落格隻能讓你入門,要深入研究還需要自己去挖掘:http://www.opencv.org.cn/opencvdoc/2.3.2/html/index.html

OpenCV人臉檢測與人臉識别

圖3 學會搜尋

By tkorays(http://blog.csdn.net/tkorays)