如何使用 Opencv 實現人臉檢測和人臉識別?
Note:
使用人臉識別需要自行編譯 Opencv 第三方模塊,地址如下:
https://github.com/opencv/opencv_contrib
1.人臉檢測 CascadeClassifier
- 加載 Opencv 自帶的人臉檢測
haarcascade_frontalface_alt.xml
分類器。 - 圖像預處理
cvtColor(灰度化)
equalizeHist(直方圖均衡化)
。 - 使用
detectMultiScale
函數進行識別。 - 使用
rectangle
函數繪制找到的目標矩形框。 - 在原圖像上
ROI
截取彩色的人臉保存。
2.人臉識別 FaceRecognizer
FisherFaceRecognizer
LBPHFaceRecognizer
2.1 人臉識別分類器訓練
- 樣本歸一化,即圖像大小一致、灰度化、直方圖均衡化等。
Ptr<FaceRecognizer> face = EigenFaceRecognizer::create()
。- 創建樣本和標簽向量
std::vector<Mat> images
std::vector<int> labels
並push_back
加入樣本和標簽。 - 進行訓練
face->train(images,labels)
。 - 保存訓練的分類器
face->save("face.xml")
。
2.2 人臉識別分類器加載和使用
- 加載訓練好的分類器
face->load(face.xml)
。 - 待識別圖像預處理
resize
cvtColor
等。 - 預測輸入圖像獲取標簽值
int label = face->predict(Mat src)
,當然也可以獲取置信度
來調整閾值
。 - 根據標簽值,繪制
putText
對應的角色名。
Note:
1.訓練和預測的圖像大小必須一樣且為灰度圖像。
2.使用 FisherFaceRecognizer 標簽必須大於2類
Code
//人臉檢測
#include "opencv2/opencv.hpp"
#include "opencv2/face.hpp"
#include <iostream>
#include <string>
using namespace cv;
using namespace cv::face;
using namespace std;
void FindFaces(cv::Mat &dst)
{
Mat src = imread("src.jpg");
Mat frame = src.clone();
Mat facesRIO;
//圖像縮放,采用雙線性插值。
//cv::resize(src,src,Size(128,128),0,0,cv::INTER_LINEAR);
//圖像灰度化。
cv::cvtColor(src,src,COLOR_BGR2GRAY);
//直方圖均衡化,圖像增強,暗的變亮,亮的變暗。
cv::equalizeHist(src,src);
//
String face_cascade_name = "haarcascade_frontalface_alt.xml";
String eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade,eyes_cascade;
if(!face_cascade.load(face_cascade_name))
{
//加載臉部分類器失敗!
return;
}
if(!eyes_cascade.load(eyes_cascade_name))
{
//加載眼睛分類器失敗!
return;
}
//存儲找到的臉部矩形。
std::vector<Rect> faces;
face_cascade.detectMultiScale(src,faces,1.1,2,0|CASCADE_SCALE_IMAGE,Size(30,30));
for(size_t i=0;i<faces.size();++i)
{
//繪制矩形 BGR。
rectangle(frame,faces[i],Scalar(0,0,255),1);
//獲取矩形中心點。
//Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
//繪制圓形。
//ellipse(frame, center, Size( faces[i].width/2, faces[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
//獲取臉部矩形區域。
//Mat faceROI = src(faces[i]);
//存儲找到的眼睛矩形。
//std::vector<Rect> eyes;
//eyes_cascade.detectMultiScale(faceROI,eyes,1.1,2,0 |CASCADE_SCALE_IMAGE,Size(30,30));
//for(size_t j=0;j<eyes.size();++j)
//{
//Point eye_center(faces[i].x + eyes[j].x + eyes[j].width/2,faces[i].y + eyes[j].y + eyes[j].height/2);
//int radius = cvRound((eyes[j].width + eyes[j].height)*0.25);
//circle(frame,eye_center,radius,Scalar( 255, 0, 0 ),4,8,0);
//}
//截取人臉。
facesROI = frame(faces[i]);
//圖像縮放。
cv::resize(facesROI,facesROI,Size(128,128),0,0,cv::INTER_LINEAR);
//保存圖像。
dst = facesROI;
cv::imwrite("dst.jpg",facesROI);
}
return;
}
//人臉識別
void Distinguish()
{
/*******************************************************
*假定 標簽1代表張三 標簽2代表李四 標簽3代表 王五
******************************************************/
//定義保存圖片和標簽的向量容器
std::vector<Mat> images;
std::vector<int> labels;
//讀取樣本
Mat src_1 = imread("src_1.jpg",CV_LOAD_IMAGE_GRAYSCALE);
Mat src_2 = imread("src_2.jpg",CV_LOAD_IMAGE_GRAYSCALE);
Mat src_3 = imread("src_3.jpg",CV_LOAD_IMAGE_GRAYSCALE);
Mat src_4 = imread("src_4.jpg",CV_LOAD_IMAGE_GRAYSCALE);
//預測樣本
Mat src_5 = imread("src_5.jpg",CV_LOAD_IMAGE_GRAYSCALE);
//圖像大小歸一化
cv::resize(src_1,src_1,Size(128,128));
cv::resize(src_2,src_2,Size(128,128));
cv::resize(src_3,src_3,Size(128,128));
cv::resize(src_4,src_4,Size(128,128));
cv::resize(src_5,src_5,Size(128,128));
//加入圖像
images.push_back(src_1);
images.push_back(src_2);
images.push_back(src_3);
images.push_back(src_4);
//加入標簽
labels.push_back(1);
labels.push_back(1);
labels.push_back(2);
labels.push_back(3);
Ptr<FaceRecognizer> faceClass = EigenFaceRecognizer::create();
Ptr<FisherFaceRecognizer> fisherClass = FisherFaceRecognizer::create();
Ptr<LBPHFaceRecognizer> lpbhClass = LBPHFaceRecognizer::create();
//訓練
faceClass->train(images,labels);
fisherClass->train(images,labels);
lpbhClass->train(images,labels);
//保存訓練的分類器
faceClass->save("faceClass.xml");
fisherClass->save("fisherClass.xml");
lpbhClass->save("lpbhClass.xml");
//加載分類器
//faceClass->load("faceClass.xml");
//fisherClass->load("fisherClass.xml");
//lpbhClass->load("lpbhClass.xml");
//使用訓練好的分類器進行預測。
int faceResult = faceClass->predict(src_5);
switch (faceResult)
{
case 1:
//張三
break;
case 2:
//李四
break;
case 3:
//王五
break;
default:
//未知
break;
}
//預測樣本並獲取標簽和置信度
int fisherResult = -1;
double fisherConfidence = 0.0;
fisherClass->predict(src_5,fisherResult,fisherConfidence);
std::count<<String("標簽類別:")<<fisherResult<<String("置信度:")<<fisherConfidence<<std::endl;
int lpbhResult = lpbhClass->predict(src_5);
std::count<<String("標簽類別:")<<lpbhResult;
return;
}
更多信息請自行查看官網參考 Opencv 3.3.0 官方教程