如何通过OpenCV人脸识别模块获得更好的结果

5
我正在尝试使用OpenCV的人脸识别模块从视频中识别出2个主体。我从视频中剪切了30张第一个主体和20张第二个主体的人脸图像,并将它们用作我的训练集。
我已经测试了所有三种方法(特征脸、费舍尔脸和LBP直方图),但是在这些方法中都没有得到好的结果。有时第一个主体被分类为第二个主体,反之亦然;有时虚假检测被归类为两个主题中的一个,有时视频中的其他人被归类为两个主题中的一个。
如何提高性能?扩大训练集是否有助于改善结果?是否有其他可以考虑在C ++中执行人脸识别的软件包?我认为这应该是一个简单的任务,因为我只想识别两个不同的主体。
以下是我的代码(我正在使用Windows 8上的OpenCV 2.4.7和VS2012):
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/contrib/contrib.hpp"


#include <iostream>
#include <stdio.h>
#include <fstream>
#include <sstream>

#define EIGEN 0
#define FISHER 0
#define LBPH 1;
using namespace std;
using namespace cv;

/** Function Headers */
void detectAndDisplay( Mat frame , int i,Ptr<FaceRecognizer> model);


static Mat toGrayscale(InputArray _src) {
    Mat src = _src.getMat();
    // only allow one channel
    if(src.channels() != 1) {
        CV_Error(CV_StsBadArg, "Only Matrices with one channel are supported");
    }
    // create and return normalized image
    Mat dst;
    cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
    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()));
        }
    }
}

/** Global variables */
String face_cascade_name = "C:\\OIM\\code\\OIM2 - face detection\\Debug\\haarcascade_frontalface_alt.xml";
//String face_cascade_name = "C:\\OIM\\code\\OIM2 - face detection\\Debug\\NewCascade.xml";
//String face_cascade_name = "C:\\OIM\\code\\OIM2 - face detection\\Debug\\haarcascade_eye_tree_eyeglasses.xml";

String eyes_cascade_name = "C:\\OIM\\code\\OIM2 - face detection\\Debug\\haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
string window_name = "Capture - Face detection";
RNG rng(12345);

/** @function main */
int main( int argc, const char** argv )
{

     string fn_csv = "C:\\OIM\\faces_org.csv";

     // These vectors hold the images and corresponding labels.
    vector<Mat> images;
    vector<int> labels;
    // Read in the data. This can fail if no valid
    // input filename is given.
    try {
        read_csv(fn_csv, images, labels);
    } catch (cv::Exception& e) {
        cerr << "Error opening file \"" << fn_csv << "\". 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);
    }
    // Get the height from the first image. We'll need this
    // later in code to reshape the images to their original
    // size:
    int height = images[0].rows;

      // The following lines create an Eigenfaces model for
    // face recognition and train it with the images and
    // labels read from the given CSV file.
    // This here is a full PCA, if you just want to keep
    // 10 principal components (read Eigenfaces), then call
    // the factory method like this:
    //
    //      cv::createEigenFaceRecognizer(10);
    //
    // If you want to create a FaceRecognizer with a
    // confidennce threshold, call it with:
    //
    //      cv::createEigenFaceRecognizer(10, 123.0);
    //
    //Ptr<FaceRecognizer> model = createEigenFaceRecognizer();
#if EIGEN
    Ptr<FaceRecognizer> model = createEigenFaceRecognizer(10,2000000000);
#elif FISHER
    Ptr<FaceRecognizer> model = createFisherFaceRecognizer(0, 200000000);
#elif LBPH
    Ptr<FaceRecognizer> model =createLBPHFaceRecognizer(1,8,8,8,200000000);
#endif
    model->train(images, labels);


    Mat frame;

    //-- 1. Load the cascades
    if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading\n"); return -1; };
    if( !eyes_cascade.load( eyes_cascade_name ) ){ printf("--(!)Error loading\n"); return -1; };

    // Get the frame rate
    bool stop(false);
    int count=1;

    char filename[512];
    for (int i=1;i<=517;i++){
        sprintf(filename,"C:\\OIM\\original_frames2\\image%d.jpg",i);
        Mat frame=imread(filename);

        detectAndDisplay(frame,i,model);
        waitKey(0);
    }
    return 0;
}

/** @function detectAndDisplay */
void detectAndDisplay( Mat frame ,int i, Ptr<FaceRecognizer> model)
{

    std::vector<Rect> faces;
    Mat frame_gray;

    cvtColor( frame, frame_gray, CV_BGR2GRAY );
    equalizeHist( frame_gray, frame_gray );

    //-- Detect faces
    //face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
    face_cascade.detectMultiScale( frame_gray, faces, 1.1, 1, 0|CV_HAAR_SCALE_IMAGE, Size(10, 10) );



    for( size_t i = 0; i < faces.size(); i++ )
    {
        Rect roi = Rect(faces[i].x,faces[i].y,faces[i].width,faces[i].height);
        Mat face=frame_gray(roi);
        resize(face,face,Size(200,200));
         int predictedLabel = -1;
        double confidence = 0.0;
        model->predict(face, predictedLabel, confidence);

        //imshow("gil",face);
        //waitKey(0);
#if EIGEN
        int M=10000;
#elif FISHER
        int M=500;
#elif LBPH
        int M=300;
#endif
        Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
        if ((predictedLabel==1)&& (confidence<M)) 
            ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 0, 0, 255 ), 4, 8, 0 );
        if ((predictedLabel==0)&& (confidence<M)) 
            ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 0), 4, 8, 0 );
        if  (confidence>M) 
            ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 0, 255, 0), 4, 8, 0 );

        Mat faceROI = frame_gray( faces[i] );
        std::vector<Rect> eyes;

        //-- In each face, detect eyes
        eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CV_HAAR_SCALE_IMAGE, Size(30, 30) );

        for( size_t j = 0; j < eyes.size(); j++ )
        {
            Point center( faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5 );
            int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
            //circle( frame, center, radius, Scalar( 255, 0, 0 ), 4, 8, 0 );
        }
    }
    //-- Show what you got
    //imshow( window_name, frame );
    char filename[512];
    sprintf(filename,"C:\\OIM\\FaceRecognitionResults\\image%d.jpg",i);
    imwrite(filename,frame);
}

提前致谢,

Gil。


扩大训练集可能会有很大帮助。 - herohuyongtao
谢谢,@herohuyongtao,训练集应该有多大? - GilLevi
尝试每个样本大约100次,看看效果如何。如果有帮助,那么你就走在了正确的道路上。 - herohuyongtao
您好先生!您是否已经得到了这个问题的好答案?如果是的话,请与我分享如何做。非常感谢! - Bahramdun Adil
我转向了深度学习方法。 - GilLevi
@GilLevi 你是如何使用深度学习方法实现人脸识别的?如果你能提供一些建议就太好了。与OpenCV相比,结果如何?谢谢! - Bahramdun Adil
1个回答

11

首先,如评论所述,如果可能的话增加样本数量。还要包括您认为视频中会出现的变化(如光照、轻微姿势等)。但是,对于特征脸/费舍尔脸,使用过多的图像并不能提高性能。不幸的是,最佳训练样本数量取决于您的数据。

更重要的一点是问题的难度完全取决于您的视频。如果您的视频包含光照、姿态等变化,则不能指望仅使用外观为基础的方法(例如特征脸)和纹理描述符(LBP)会成功。首先,您可能需要检测人脸。然后:

  • 你可能想估计脸部位置并将其变形为正面;检查主动外观模型和主动形状模型
  • 使用均衡化直方图来减轻光照问题
  • 将椭圆拟合到检测到的面部区域可以帮助抵抗背景噪声。

当然,在文献中还有许多其他方法可用;我写的步骤在OpenCV中实现并且广泛知晓。

希望这能帮到您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接