如何使用 Opencv 实现人脸检测和人脸识别?

如何使用 Opencv 实现人脸检测和人脸识别?

Note:

使用人脸识别需要自行编译 Opencv 第三方模块,地址如下:
https://github.com/opencv/opencv_contrib

1.人脸检测 CascadeClassifier

  1. 加载 Opencv 自带的人脸检测 haarcascade_frontalface_alt.xml 分类器。
  2. 图像预处理 cvtColor(灰度化) equalizeHist(直方图均衡化)
  3. 使用 detectMultiScale 函数进行识别。
  4. 使用 rectangle 函数绘制找到的目标矩形框。
  5. 在原图像上 ROI 截取彩色的人脸保存。

2.人脸识别 FaceRecognizer FisherFaceRecognizer LBPHFaceRecognizer

2.1 人脸识别分类器训练

  1. 样本归一化,即图像大小一致、灰度化、直方图均衡化等。
  2. Ptr<FaceRecognizer> face = EigenFaceRecognizer::create()
  3. 创建样本和标签向量 std::vector<Mat> images std::vector<int> labelspush_back 加入样本和标签。
  4. 进行训练 face->train(images,labels)
  5. 保存训练的分类器 face->save("face.xml")

2.2 人脸识别分类器加载和使用

  1. 加载训练好的分类器 face->load(face.xml)
  2. 待识别图像预处理 resize cvtColor 等。
  3. 预测输入图像获取标签值 int label = face->predict(Mat src),当然也可以获取 置信度 来调整 阈值
  4. 根据标签值,绘制 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 官方教程

posted @ 2017-10-08 01:47  學海無涯  阅读(47379)  评论(1编辑  收藏  举报