• 人脸和性别识别(基于OpenCV)


    描写叙述

    人脸识别包含四个步骤

    1. 人脸检測:定位人脸区域,仅仅关心是不是脸;
    2. 人脸预处理:对人脸检測出来的图片进行调整优化。
    3. 收集和学习人脸:收集要识别的人的预处理过的人脸,然后通过一些算法去学习怎样识别;
    4. 人脸识别:识别当前人脸与数据库里的哪个人脸最类似。

    人脸检測

    OpenCV集成了基于PCA LDA 和LBP的人脸检測器。源文件自带非常多各种训练好的检測器。下表是经常使用的XML文件
    这里写图片描写叙述
    上面的XML文件能够检測正面人脸、眼睛或鼻子。检測人脸我採用的是第一个或第二个Harr人脸检測器。

    识别率比較好。

    第一步:载入Harr人脸检測XML文件

    try{
            faceCascade.load(faceCascadeFilename);
        }catch(cv::Exception& e){}
    
            if ( faceCascade.empty() ) {
            cerr << "ERROR: Could not load Face Detection cascade classifier [" << faceCascadeFilename << "]!" << endl;
            cerr << "Copy the file from your OpenCV data folder (eg: 'C:\OpenCV\data\haarcascade_frontalface_alt2') into this WebcamFaceRec folder." << endl;
            exit(1);
        }
        cout << "Loaded the Face Detection cascade classifier [" << faceCascadeFilename << "]." << endl;

    第二步:载入摄像头,从视频获取图像帧。

    try{
            videoCapture.open(CameraID);
        }catch(cv::Exception& e){}
    
        if(!videoCapture.isOpened()){
            cerr << "ERROR: could not open Camera!" << endl;
            exit(1);
        }
    
    videoCapture >> cameraFrame;

    第三步:一帧图像预处理

    1、 灰度转换:使用cvtColor()函数,将彩色图像转换为灰度图像。台式机是3通道的BGR。移动设备则是4通道的BGRA格式

    if(srcimg.channels() ==3 ){
             cvtColor(srcimg,gray_img,CV_BGR2GRAY);
         }
        else if(srcimg.channels() ==4 ){
             cvtColor(srcimg,gray_img,CV_BGRA2GRAY);
         }
        else {
             gray_img = srcimg;
         }

    2、直方图均衡化,在OpenCV函数中利用equalizeHist()函数运行直方图均衡化,提升对照度和亮度。

    equalizeHist(gray_img,equalized_Img);

    第四步:检測人脸

    上面已经创建了级联分类器并载入好XML文件。接着使用函数Classifier::detecMultiScale()函数来检測人脸。这个函数的參数说明:
    a、minFeatureSize: 该參数决定最小的人脸大小。通常能够设为20*20或30*30像素。假设使用摄像机或移动设备检測,则人脸一般非常接近摄像机,可把參数调大。80*80;
    b、searchScaleFactor: 该參数决定有多少不同大小的人脸要搜索,通常设为1.1
    c、minNeighbors: 该參数决定检測器怎样确定人脸已经被检測到。通常设为3
    d、flags: 该參数设定是否要查找全部的人脸或最大的人脸
    (CASCADE_FIND_BIGGEST_OBJECT)

    int flags = CASCADE_FIND_BIGGEST_OBJECT;
        //smallest object Size
        Size minFeatureSize = Size(20,20);
        // How detailed should the search be. Must be larger than 1.0.
        float searchScaleFactor = 1.1f;
        // How much the detections should be filtered out. This should depend on how bad false detections are to your system.
        // minNeighbors=2 means lots of good+bad detections, and minNeighbors=6 means only good detections are given but some are missed.
        int minNeighbors = 6;
        vector<Rect> faces;
        faceCascade.detectMultiScale(dectImg,faces,searchScaleFactor,
                                        minNeighbors,flags,minFeatureSize);
        //faceCascade.detectMultiScale(equalized_Img, faces);
        int i = 0;
        for(i = 0; i < faces.size(); i++){
            Rect face_id = faces[i];
            rectangle(orginalimg,face_id,Scalar(0,255,0),1);
        }

    人脸识别

    为了识别人脸。须要收集足够多的要识别的人的人脸图像。

    收集好之后,选择适合人脸识别的机器学习算法。通过算法来学习收集的数据。从而训练出一个模型并保存。下次进来一帧图像,通过算法对模型里的參数进行匹配识别。人脸识别机器学习算法有非常多,如SVM(支持向量机),ANN(人工神经网络)还有最经常使用的是基于特征脸的算法。OpenCV提供了CV::Algorithm类,类中有基于特征脸的(PCA 主成分分析)、Fisher脸(LDA 线性判别分析)和LPBH(局部二值模式直方图)

    使用里面的算法,第一步必须通过cv::Algorithm::creat< FaceRecognizer>创建一个FaceRecognizer对象。创建了FaceRecognizer对象之后。将收集的人脸数据和标签传递给FaceRecognizer::train() 函数就可以进行训练模型。

    string facerecAlgorithm = "FaceRecognizer.Fisherfaces";
    Ptr<FaceRecognizer> model;
    // Use OpenCV's new FaceRecognizer in the "contrib" module:
    model = Algorithm::create<FaceRecognizer>(facerecAlgorithm);
    if (model.empty()) {
    cerr << "ERROR: The FaceRecognizer [" << facerecAlgorithm;
     cerr << "] is not available in your version of OpenCV. ";
     cerr << "Please update to OpenCV v2.4.1 or newer." << endl;
     exit(1);
    }
    
    model->train(preprocessedFaces, faceLabels);

    训练好模型之后。通常是把模型保存下来,以免下次反复训练。

    直接载入模型就可以。下一步就是人脸识别。相同,opencv把识别算法集成在FaceRecognizer类中。简单地调用FaceRecognizer::predict() 就能够识别。

    int identity = model->predict(preprocessedFace);

    測试程序

    /*
     * Copyright (c) 2011. Philipp Wagner <bytefish[at]gmx[dot]de>.
     * Released to public domain under terms of the BSD Simplified license.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are met:
     *   * Redistributions of source code must retain the above copyright
     *     notice, this list of conditions and the following disclaimer.
     *   * Redistributions in binary form must reproduce the above copyright
     *     notice, this list of conditions and the following disclaimer in the
     *     documentation and/or other materials provided with the distribution.
     *   * Neither the name of the organization nor the names of its contributors
     *     may be used to endorse or promote products derived from this software
     *     without specific prior written permission.
     *
     *   See <http://www.opensource.org/licenses/bsd-license>
     */
    
    #include "opencv2/core/core.hpp"
    #include "opencv2/contrib/contrib.hpp"
    #include "opencv2/highgui/highgui.hpp"
    
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <direct.h>
    
    using namespace cv;
    using namespace std;
    
    //const char *faceCascadeFilename = "C:\opencv\sources\data\lbpcascades\lbpcascade_frontalface.xml"; 
    const char *faceCascadeFilename = "C:\opencv\sources\data\haarcascades\haarcascade_frontalface_alt2.xml"; 
    const char *eyeCascadeFilename1 = "C:\opencv\sources\data\haarcascades\haarcascade_eye.xml";               // Basic eye detector for open eyes only.
    const char *eyeCascadeFilename2 = "C:\opencv\sources\data\haarcascades\haarcascade_eye_tree_eyeglasses.xml";
    const char *face_lib            = "face_train_img//";
    
    const int DESIRED_CAMERA_WIDTH = 640;
    const int DESIRED_CAMERA_HEIGHT = 480;
    const int Width = 92;
    const int Height = 112;
    int gender_width;
    int gender_height;
    int im_width;
    int im_height;
    
    string g_listname_t[]= 
    {
        "Jack",
        "William",
        "huang",
        "Barton"
    };
    
    
    static Mat norm_0_255(InputArray _src) {
        Mat src = _src.getMat();
        // Create and return normalized image:
        Mat dst;
        switch(src.channels()) {
        case 1:
            cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
            break;
        case 3:
            cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
            break;
        default:
            src.copyTo(dst);
            break;
        }
        return dst;
    }
    
    static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
        std::ifstream file(filename.c_str(), ifstream::in);
        if (!file) {
            string error_message = "No valid input file was given, please check the given filename.";
            CV_Error(CV_StsBadArg, error_message);
        }
        string line, path, classlabel;
        while (getline(file, line)) {
            stringstream liness(line);
            getline(liness, path, separator);
            getline(liness, classlabel);
            if(!path.empty() && !classlabel.empty()) {
                images.push_back(imread(path, 0));
                labels.push_back(atoi(classlabel.c_str()));
            }
        }
    }
    
    static void InitVideoCapture(VideoCapture &videoCapture, int CameraID)
    {
        try{
            videoCapture.open(CameraID);
        }catch(cv::Exception& e){}
    
        if(!videoCapture.isOpened()){
            cerr << "ERROR: could not open Camera!" << endl;
            exit(1);
        }
    
        videoCapture.set(CV_CAP_PROP_FRAME_WIDTH, DESIRED_CAMERA_WIDTH);
        videoCapture.set(CV_CAP_PROP_FRAME_HEIGHT, DESIRED_CAMERA_HEIGHT);
    
        cout << "CameraID is :" << CameraID << endl;
    
    
    }
    
    static void InitDetectors(CascadeClassifier &faceCascade, CascadeClassifier &eyeCascade1, CascadeClassifier &eyeCascade2)
    {
        try{
            faceCascade.load(faceCascadeFilename);
        }catch(cv::Exception& e){}
    
            if ( faceCascade.empty() ) {
            cerr << "ERROR: Could not load Face Detection cascade classifier [" << faceCascadeFilename << "]!" << endl;
            cerr << "Copy the file from your OpenCV data folder (eg: 'C:\OpenCV\data\haarcascade_frontalface_alt2') into this WebcamFaceRec folder." << endl;
            exit(1);
        }
        cout << "Loaded the Face Detection cascade classifier [" << faceCascadeFilename << "]." << endl;
    
        // Load the Eye Detection cascade classifier xml file.
        try {   // Surround the OpenCV call by a try/catch block so we can give a useful error message!
            eyeCascade1.load(eyeCascadeFilename1);
        } catch (cv::Exception& e) {}
        if ( eyeCascade1.empty() ) {
            cerr << "ERROR: Could not load 1st Eye Detection cascade classifier [" << eyeCascadeFilename1 << "]!" << endl;
            cerr << "Copy the file from your OpenCV data folder (eg: 'C:\OpenCV\data\haarcascades') into this WebcamFaceRec folder." << endl;
            exit(1);
        }
        cout << "Loaded the 1st Eye Detection cascade classifier [" << eyeCascadeFilename1 << "]." << endl;
    
        // Load the Eye Detection cascade classifier xml file.
        try {   // Surround the OpenCV call by a try/catch block so we can give a useful error message!
            eyeCascade2.load(eyeCascadeFilename2);
        } catch (cv::Exception& e) {}
        if ( eyeCascade2.empty() ) {
            cerr << "Could not load 2nd Eye Detection cascade classifier [" << eyeCascadeFilename2 << "]." << endl;
            // Dont exit if the 2nd eye detector did not load, because we have the 1st eye detector at least.
            //exit(1);
        }
        else
            cout << "Loaded the 2nd Eye Detection cascade classifier [" << eyeCascadeFilename2 << "]." << endl;
    
    
    }
    
    void readDataTraining(Ptr<FaceRecognizer> &model,vector<Mat> &images,vector<int> &labels,string &filePath )
    {
    
        // These vectors hold the images and corresponding labels.
    
        // Read in the data. This can fail if no valid
        // input filename is given.
        try {
            read_csv(filePath, images, labels);
        } catch (cv::Exception& e) {
            cerr << "Error opening file "" << filePath << "". Reason: " << e.msg << endl;
            // nothing more we can do
            exit(1);
        }
        // Quit if there are not enough images for this demo.
        if(images.size() <= 1) {
            string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!";
            CV_Error(CV_StsError, error_message);
        }
    
    
    /*    Mat testSample = images[images.size() - 1];
        int testLabel = labels[labels.size() - 1];
        images.pop_back();
        labels.pop_back();*/
    
    
        model->train(images, labels);
        //int predictedLabel = model->predict(testSample);
        //
        // To get the confidence of a prediction call the model with:
        //
        //      int predictedLabel = -1;
        //      double confidence = 0.0;
        //      model->predict(testSample, predictedLabel, confidence);
        //
        /*string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
        cout << result_message << endl;*/
    }
    
    
    void preprocessing(Mat &srcimg, Mat &dstimg)
    {
        Mat gray_img;
        if(srcimg.channels() ==3 ){
             cvtColor(srcimg,gray_img,CV_BGR2GRAY);
         }
        else if(srcimg.channels() ==4 ){
             cvtColor(srcimg,gray_img,CV_BGRA2GRAY);
         }
        else {
             gray_img = srcimg;
         }
    
         /*Mat equalized_Img;
         equalizeHist(gray_img,equalized_Img);*/
        dstimg = gray_img;
    }
    
    
    void faceDectRecog(CascadeClassifier &faceCascade,Ptr<FaceRecognizer> &model,Ptr<FaceRecognizer> &gender_model,Ptr<FaceRecognizer> &fishermodel,Mat &orginalimg,Mat &dectImg)
    {
        static int num = 0;
        int predictedLabel = 0;
        int gender_predict = 0;
        // Only search for just 1 object (the biggest in the image).
        int flags = CASCADE_FIND_BIGGEST_OBJECT;
        //smallest object Size
        Size minFeatureSize = Size(20,20);
        // How detailed should the search be. Must be larger than 1.0.
        float searchScaleFactor = 1.1f;
        // How much the detections should be filtered out. This should depend on how bad false detections are to your system.
        // minNeighbors=2 means lots of good+bad detections, and minNeighbors=6 means only good detections are given but some are missed.
        int minNeighbors = 8;
        vector<Rect> faces;
        faceCascade.detectMultiScale(dectImg,faces,searchScaleFactor,
                                        minNeighbors,flags,minFeatureSize);
        //faceCascade.detectMultiScale(equalized_Img, faces);
    
    /*  pca + Lda
        Mat eigenvalues = gender_model->getMat("eigenvalues");//提取model中的特征值,该特征值默认由大到小排列  
        Mat W = gender_model->getMat("eigenvectors");//提取model中的特征向量,特征向量的排列方式与特征值排列顺序一一相应  
        int xth = 121;//打算保留前121个特征向量,代码中没有体现原因,但选择121是经过斟酌的,首先,在我的实验中,"前121个特征值之和/全部特征值总和>0.97";其次,121=11^2,能够将结果表示成一个11*11的2维图像方阵,交给fisherface去计算。  
        //vector<Mat> reduceDemensionimages;//降维后的图像矩阵  
        Mat evs = Mat(W, Range::all(), Range(0, xth));//选择前xth个特征向量,其余舍弃
        Mat mean = gender_model->getMat("mean"); */
    
    
        int i = 0;
        for(i = 0; i < faces.size(); i++){
            Rect face_id = faces[i];
    
            Mat face = dectImg(face_id);
    
            Mat face_resized;
            Mat gender_resized;
            cv::resize(face, face_resized, Size(im_width, im_height), 1.0, 1.0, INTER_CUBIC);
            cv::resize(face, gender_resized, Size(gender_width, gender_height), 1.0, 1.0, INTER_CUBIC);
    
    
            rectangle(orginalimg,face_id,Scalar(0,255,0),1);
    
            predictedLabel = model->predict(face_resized);
    
            string result_message;
            /*result_message = format("Predicted  = %d ", predictedLabel);
            cout << result_message << endl;*/
    /*          PCA +LDA
            Mat projection = subspaceProject(evs, mean, gender_resized.reshape(1,1));//做子空间投影  
            //reduceDemensionimages.push_back(projection.reshape(1,sqrt(xth*1.0)));
            Mat reduceDemensionimages = projection.reshape(1,sqrt(xth*1.0));
            gender_predict = fishermodel->predict(reduceDemensionimages);*/
    
            string box_text;
            box_text = format( "Prediction = " );
    
    
            if ( predictedLabel >= 0 && predictedLabel <=3 )
            {
                box_text.append( g_listname_t[predictedLabel] );
            }
            else box_text.append( "Unknown" );
    
            gender_predict = gender_model->predict(face_resized);
            if(gender_predict == 0)
            {
                result_message = format("Predicted: female");
                box_text.append( "   female" );
            }
    
            else if (gender_predict == 1)
            {
                result_message = format("Predicted: male");
                box_text.append( "   male" );
            }
    
            else result_message = format("Predicted: Unknow");
            cout << result_message << endl;
            // Calculate the position for annotated text (make sure we don't
            // put illegal values in there):
            int pos_x = std::max(face_id.tl().x - 10, 0);
            int pos_y = std::max(face_id.tl().y - 10, 0);
            // And now put it into the image:
             putText(orginalimg, box_text, Point(pos_x, pos_y), FONT_HERSHEY_PLAIN, 1.0, CV_RGB(0,255,0), 2.0);
    
        }
    }
    
    
    void faceDect(CascadeClassifier &faceCascade,Mat &orginalimg,Mat &dectImg)
    {
    
        // Only search for just 1 object (the biggest in the image).
        int flags = CASCADE_FIND_BIGGEST_OBJECT;
        //smallest object Size
        Size minFeatureSize = Size(20,20);
        // How detailed should the search be. Must be larger than 1.0.
        float searchScaleFactor = 1.1f;
        // How much the detections should be filtered out. This should depend on how bad false detections are to your system.
        // minNeighbors=2 means lots of good+bad detections, and minNeighbors=6 means only good detections are given but some are missed.
        int minNeighbors = 6;
        vector<Rect> faces;
        faceCascade.detectMultiScale(dectImg,faces,searchScaleFactor,
                                        minNeighbors,flags,minFeatureSize);
        //faceCascade.detectMultiScale(equalized_Img, faces);
        int i = 0;
        for(i = 0; i < faces.size(); i++){
            Rect face_id = faces[i];
            rectangle(orginalimg,face_id,Scalar(0,255,0),1);
        }
    }
    
    void CaptureFace(CascadeClassifier &faceCascade,Ptr<FaceRecognizer> &model,Mat &orginalimg,Mat &dectImg)
    {
        static int num = 0;
        // Only search for just 1 object (the biggest in the image).
        int flags = CASCADE_FIND_BIGGEST_OBJECT;
        //smallest object Size
        Size minFeatureSize = Size(20,20);
        // How detailed should the search be. Must be larger than 1.0.
        float searchScaleFactor = 1.1f;
        // How much the detections should be filtered out. This should depend on how bad false detections are to your system.
        // minNeighbors=2 means lots of good+bad detections, and minNeighbors=6 means only good detections are given but some are missed.
        int minNeighbors = 6;
        vector<Rect> faces;
        faceCascade.detectMultiScale(dectImg,faces,searchScaleFactor,
                                        minNeighbors,flags,minFeatureSize);
        //faceCascade.detectMultiScale(equalized_Img, faces);
        int i = 0;
        for(i = 0; i < faces.size(); i++){
            Rect face_id = faces[i];
    
            Mat face = dectImg(face_id);
    
            Mat face_resized;
            cv::resize(face, face_resized, Size(im_width, im_height), 1.0, 1.0, INTER_CUBIC);
    
            char c[4];
            itoa(num,c,10);
            string s = face_lib + (string)c + ".png";
            imwrite(s,face_resized);
            cout << "Capture the" << num << "face" << endl;
            cout << s << ";" << face_id << endl;
            num ++;
    
            rectangle(orginalimg,face_id,Scalar(0,255,0),1);
        }
    }
    
    
    
    int main(int argc, const char *argv[]) 
    {
        int mode;
        int i;
    
        // Get the path to your CSV.
        string fn_csv = string("at.txt");
        string gender_csv = string("gender.txt");
        string temp_csv = string("test.txt");
        CascadeClassifier faceCascade;
        CascadeClassifier eyeCascade1;
        CascadeClassifier eyeCascade2;
        VideoCapture videoCapture;
        Ptr<FaceRecognizer> model;
        Ptr<FaceRecognizer> temp_model;
        Ptr<FaceRecognizer> gender_model;
        int CameraID = 0;
    
        vector<Mat> images;
        vector<int> labels;
    
        vector<Mat> temp_images;
        vector<int> temp_labels;
    
        vector<Mat> gender_images;
        vector<int> gender_labels;
        cout << "Compiled with OpenCV version " << CV_VERSION << endl << endl;
    
        InitDetectors(faceCascade,eyeCascade1,eyeCascade2);
    
        InitVideoCapture(videoCapture,CameraID);
    
        printf("
    ");
        printf("FaceDec and Recognition V0.1
    ");
        printf("Usage: mode 0 : FaceDect; 1: train your own face; 2: Recognition 
    ");
        printf("please input mode
    ");
        scanf("%d",&mode);
    
        //model = createEigenFaceRecognizer();
        temp_model = createEigenFaceRecognizer();
        model =createEigenFaceRecognizer();
        gender_model =createEigenFaceRecognizer();
    
        Ptr<FaceRecognizer> fishermodel = createFisherFaceRecognizer();  
    
    
        //gender_model = createEigenFaceRecognizer();
    
        if(mode == 3)
        {
            readDataTraining(model,images,labels,fn_csv);
            readDataTraining(gender_model,gender_images,gender_labels,gender_csv);
            gender_width = gender_images[0].cols;
            gender_height = gender_images[0].rows;
            im_width = images[0].cols;
            im_height = images[0].rows;
    
            model->save("Face_recog.yml");
            gender_model->save("gender_recog.yml");
        }
        //readDataTraining(temp_model,temp_images,gender_labels,temp_csv);
    
    
    
    
    
    
        model->load("Face_recog.yml");
    
        gender_width = Width;
        gender_height = Height;
        im_width = Width;
        im_height = Height;
    
        gender_model->load("eigenface_gender.yml");//保存训练结果,供检測时使用  
        fishermodel->load("fisher.yml");
    
        printf("gender_width :%d gender_height :%d im_ %d im_height:%d
    ",gender_width,gender_height,im_width,im_height);
    
    
        int num = 0;
        Mat cameraFrame;
    
        if(mode == 4)
        {
            read_csv(temp_csv, temp_images, temp_labels);
            for(i = 0; i < temp_images.size(); i ++)
            {
                Mat temp_img;
                preprocessing(temp_images[i],temp_img);
                CaptureFace(faceCascade,temp_model,temp_images[i],temp_img);
            }
    
    
        }
        for(;;){
            videoCapture >> cameraFrame;
            if( cameraFrame.empty()){
                cerr << "Error : could not grap next frame " << endl;
            }
            Mat processFrame = cameraFrame.clone();
            Mat preprocess_img;
    
            preprocessing(processFrame,preprocess_img);
    
            switch(mode){
            case 0:
                faceDect(faceCascade,processFrame,preprocess_img);
                break;
            case 1:
                CaptureFace(faceCascade,model,processFrame,preprocess_img);
            case 2:
                faceDectRecog(faceCascade,model,gender_model,fishermodel,processFrame,preprocess_img);
            default:
                break;
            }
    
            imshow("face_recognizer",processFrame);
    
            char key = (char) waitKey(300);
            if(key == 27)
                break;
    
    
    
        }
        return 0;
    }
  • 相关阅读:
    树形DP求树的最小支配集,最小点覆盖,最大独立集
    贪心法求树的最小支配集,最小点覆盖,最大独立集
    树上两点的最近公共祖先问题(Least Common Ancestors)
    大厂前端面试题
    表单中包含上传图片
    element-ui表单验证
    一、React基础
    点击div上传图片,在img中预览
    持久化
    docker安装
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/7150153.html
Copyright © 2020-2023  润新知