C/C++ 图像处理(18)------人脸检测

人脸识别包括人脸检测和识别两个部分

一般的逻辑是先检测人脸位置,然后再识别。

具体的流程是

准备要识别的人脸数据->检测人脸->学习人脸特征并生成模型

检测人脸->对比检测出来的人脸和模型的相识度->给出识别结果

本篇文章用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;;
}

通过上面的步骤基本上就完成了一个普通的人脸识别流程,但其缺点是准确率还不是很高,要提高准确率可以考虑用深度学习的方法,后面研究到的话会写出来跟大家交流。

猜你喜欢

转载自blog.csdn.net/oHanTanYanYing/article/details/79220893