C/C++ 影象處理(18)------人臉檢測
阿新 • • 發佈:2019-01-24
人臉識別包括人臉檢測和識別兩個部分
一般的邏輯是先檢測人臉位置,然後再識別。
具體的流程是
準備要識別的人臉資料->檢測人臉->學習人臉特徵並生成模型
檢測人臉->對比檢測出來的人臉和模型的相識度->給出識別結果
本篇文章用OpenCV實現了這兩個過程,具體的程式碼有參考網上的程式碼,如有雷同,絕非巧合
具體的檢測和識別原理不在本篇文章的範疇之內,望見諒
人臉檢測
#include <time.h>
#include <opencv2/opencv.hpp>
#include <vector>//容器標頭檔案
using namespace std;
using namespace cv;
//關鍵函式
/*
void detectMultiScale(
const Mat& image,
CV_OUT vector<Rect>& objects,
double scaleFactor = 1.1,
int minNeighbors = 3,
int flags = 0,
Size minSize = Size(),
Size maxSize = Size()
);
*/
//引數1:image--待檢測圖片,一般為灰度影象加快檢測速度;
//引數2:objects--被檢測物體的矩形框向量組;
//引數3:scaleFactor--表示在前後兩次相繼的掃描中,搜尋視窗的比例係數。預設為1.1即每次搜尋視窗依次擴大10%;
//引數4:minNeighbors--表示構成檢測目標的相鄰矩形的最小個數(預設為3個)。
//如果組成檢測目標的小矩形的個數和小於 min_neighbors - 1 都會被排除。
//如果min_neighbors 為 0, 則函式不做任何操作就返回所有的被檢候選矩形框
//引數5:flags--要麼使用預設值,要麼使用CV_HAAR_DO_CANNY_PRUNING
//CV_HAAR_DO_CANNY_PRUNING--函式將會使用Canny邊緣檢測來排除邊緣過多或過少的區域,因為這些區域通常不會是人臉所在區域;
//引數6、7:minSize和maxSize用來限制得到的目標區域的範圍。
void getfaceimg()//人臉影象獲取
{
CascadeClassifier ccf;//建立臉部物件
string cascadeName = "haarcascade_frontalface_alt2.xml";//人臉檢測模型,請在OpenCV資料夾中搜索
ccf.load(cascadeName);//讀取opencv人臉檢測模型
vector<Rect> faces;//容器,存放檢測到的人臉
long time = clock();
string path;
for (size_t i = 0; i < 5; i++)
{
path = to_string(i + 1);
path.append(".jpg");
Mat img = imread(path, 0);
//imshow("原圖", img);
equalizeHist(img, img);//直方圖均衡化
//imshow("直方圖均衡化", img);
//人臉檢測
ccf.detectMultiScale(img, faces, 1.1, 3, CV_HAAR_DO_CANNY_PRUNING, Size(50, 50), Size(500, 500));//人臉檢測
for (vector<Rect>::const_iterator iter = faces.begin(); iter != faces.end(); iter++)
{
rectangle(img, *iter, Scalar(0), 2, 8); //用矩形圈出人臉
}
//擷取儲存臉部影象
Mat faceimg;
for (vector<Rect>::const_iterator iter = faces.begin(); iter != faces.end(); iter++)
{
faceimg = img(*iter);
imshow("臉部影象", faceimg);
imwrite("faceImg//" + path, faceimg);
}
imshow("檢測結果", img);
waitKey(1000);
}
cout << "花費時間:" << clock() - time << "ms" << endl;
}
void main()
{
getfaceimg();//人臉影象獲取
}
分類器訓練
//人臉分類器訓練,資料庫用的ORL人臉資料庫,並加入了要識別的人臉放在"S0"資料夾中
void TrainFaceImg()
{
//定義儲存圖片和標籤的向量容器
std::vector<Mat> images;
std::vector<int> labels;
//讀取樣本
for (size_t s = 0; s <= 40; s++)
{
String path = "att_faces//s"+ to_string(s)+"//";
for (size_t i = 1; i <= 10; i++)
{
String imgpath = path + to_string(i) + ".pgm";
Mat trainfaceimg = imread(imgpath, CV_LOAD_IMAGE_GRAYSCALE);
resize(trainfaceimg, trainfaceimg, Size(128, 128));
images.push_back(trainfaceimg);//加入影象
labels.push_back(s);//加入標籤
}
}
//三種人臉識別方法,只用其中的一種也可以
Ptr<FaceRecognizer> faceClass = createEigenFaceRecognizer();
Ptr<FaceRecognizer> fisherClass = createFisherFaceRecognizer();
Ptr<FaceRecognizer> lpbhClass = createLBPHFaceRecognizer();
//訓練
faceClass->train(images, labels);
fisherClass->train(images, labels);
lpbhClass->train(images, labels);
//儲存訓練的分類器
faceClass->save("faceClass.xml");
fisherClass->save("fisherClass.xml");
lpbhClass->save("lpbhClass.xml");
cout << "分類器訓練完成"<< endl;
}
人臉識別(注意要放進去識別的圖片是先經過檢測、裁剪和尺度變換後的圖片)
void FaceDetect()
{
Ptr<FaceRecognizer> faceClass = createEigenFaceRecognizer();
Ptr<FaceRecognizer> fisherClass = createFisherFaceRecognizer();
Ptr<FaceRecognizer> lpbhClass = createLBPHFaceRecognizer();
//載入分類器
faceClass->load("faceClass.xml");
fisherClass->load("fisherClass.xml");
lpbhClass->load("lpbhClass.xml");
//使用訓練好的分類器進行預測。
Mat detectimg = imread("faceImg//14.pgm", 0);
resize(detectimg, detectimg, Size(128, 128));
//預測樣本並獲取標籤和置信度
int faceResult = faceClass->predict(detectimg);
cout << String("faceClass標籤類別:") << faceResult << endl;;
int fisherResult = -1;
double fisherConfidence = 0.0;
fisherClass->predict(detectimg, fisherResult, fisherConfidence);
cout << String("fisherClass標籤類別:") << fisherResult << String("置信度:") << fisherConfidence << endl;
int lpbhResult = lpbhClass->predict(detectimg);
cout << String("lpbhResult標籤類別:") << lpbhResult << endl;;
}