opencv - 如何使用OpenCV人脸识别模块获得更好的结果

标签 opencv image-processing computer-vision

我正在尝试使用 OpenCV 的面部识别模块从视频中识别 2 个主题。我从视频中裁剪了第一个对象的 30 张人脸图像和第二个对象的 20 张人脸图像,并将它们用作我的训练集。

我已经测试了所有三种方法(Eigenfaces、Fisherfaces 和 LBP 直方图),但我在这两种方法中都没有得到好的结果。有时第一主题被归类为第二主题,反之亦然,有时错误检测被归类为两个主题之一,有时视频中的其他人被归类为两个主题之一。

如何提高性能?扩大训练集是否有助于改善结果?我可以考虑使用 C++ 执行人脸识别的其他软件包吗?我认为这应该是一项简单的任务,因为我只想识别两个不同的主题。

这是我的代码(我在带有 VS2012 的 Windows 8 上使用 OpenCV 2.4.7):

#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);
}

提前致谢

吉尔。

最佳答案

首先,如评论所述,尽可能增加样本数量。还包括您希望在视频中出现的变化(如照明、轻微姿势等)。然而,特别是对于 eigenfaces/fisherfaces,如此多的图像无助于提高性能。遗憾的是,训练样本的最佳数量可能取决于您的数据。

更重要的一点是问题的难易程度完全取决于你的视频。如果您的视频包含照明、姿势等变化;那么你不能指望使用纯粹基于外观的方法(例如特征脸)和纹理描述符(LBP)会成功。首先,您可能想要检测人脸。然后:

  • 您可能想要估计面部位置并扭曲到正面;查看 用于主动外观模型和主动形状模型
  • 使用均衡直方图减弱光照问题
  • 将椭圆拟合到检测到的人脸区域将有助于消除背景噪音。

当然,文献中还有很多其他方法可用;我写的步骤是在 OpenCV 中实现的,并且众所周知。

希望对您有所帮助。

关于opencv - 如何使用OpenCV人脸识别模块获得更好的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21339307/

相关文章:

opencv - 使用opencv检测棋盘上方的手

opencv - Opencv 的新 Haarcascade

Android:如何使用opencv获得良好的canny边缘检测的高低阈值

visual-studio-2008 - 使用OpenCV 2.3配置Visual Studio 2008项目

Python OpenCV : draw outer contours inside a specific contour

java - 将彩色图像转换为 Array[i][j]

python - 对服装照片进行分类有哪些好的特征?

python - 如何还原由openface.AlignDlib.align完成的转换?

opencv - 频域滤波opencv c++?

python - skimage 模块缺乏记录的功能