如何使用SVM进行人物识别?

时间:2012-11-02 17:11:42

标签: opencv image-processing svm face-recognition

我正在运行opencv 2.4.2 C ++。

我正在尝试使用opencv进行人员识别。

我正在使用包含不同方向的不同人员的VidTIMIT数据集。

我正在使用CvSVM对这些人进行分类。

我的问题是svm的输出总是一样的。

我遵循的算法是:

  1. 使用Haar进行人脸检测
  2. 调整脸部大小(58 * 58)
  3. Svm培训
  4. 分类
  5. 现在,我想知道我是否在培训中做错了什么。

    我正在尝试这种方法,考虑5(num_name)人,10(num_images)个不同的图像。

    void runFaceDetectionRecognition(vector<Mat_<uchar> > &images){
    vector<vector<Rect> > faces;
    for (unsigned i=0; i<images.size(); ++i) {
    
        /// detection face
        vector<Rect> f;
        faceDetection(images[i], f);
    
        if (!f.empty()) {
            faces.push_back(f);
    
            /// I keep only the face
            Mat_<uchar> roi = ( images[i](f[0]) );
    
            /// resize
            resize(roi, roi, Size(58, 58));
    
            roi.copyTo(images[i]);            
        }
    }
    
    /// Set up parameters
    CvSVMParams params;
    params.svm_type    = CvSVM::C_SVC;
    params.kernel_type = CvSVM::LINEAR;
    params.term_crit   = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
    
    
    /// Set up training data
    float labels[num_name][num_images];
    float label = 0;
    
    /// different label for different person
    for (unsigned i=0; i<num_name; ++i) {
        for (unsigned j=0; j<num_images; ++j)
            labels[i][j] = label;
    
        label++;
    }
    
    /// labeling matrix
    Mat labelsMat(num_name*num_images, 1, CV_32FC1, labels);
    
    /// unrolling images
    float data[images.size()][58*58];
    for (unsigned l=0; l<images.size(); ++l)
    
        for (unsigned i=0; i<58; ++i)
            for (unsigned j=0; j<58; ++j)
                data[l][j+58*i] = images[l].at<float>(i,j);
    
    
    /// training matrix
    Mat train((int) images.size(),58*58, CV_32FC1, data);
    CvSVM svm(train, labelsMat, Mat(), Mat(), params);
    
    /// Validation
    valSVM(svm, train.rowRange(0, 1));
    }
    

    验证码:

    void valSVM(CvSVM &svm, Mat train){
    
    /// prediction
    float response = svm.predict(train);
    
    cout << "Response ===> " << response << " ";
    
    /// output
    if (response == 0)  cout << "lea";
    else if (response == 1)  cout << "maria";
    else if (response == 2)  cout << "ramona";
    else if (response == 3)  cout << "teresa";
    else if (response == 4)  cout << "yan";
    }
    

    希望你能帮助我。

3 个答案:

答案 0 :(得分:4)

这里的另一个答案是不正确的说SVM必须使用PCA才能运行。我在没有PCA的128x128图像上使用了SVM,取得了很好的效果。我用cohn-kanade数据集做了类似的事情。以下是一些可能有用的源代码。

vector<Mat> preImages;//Fill this with your images from your dataset
vector<int> labels;//Fill this with the labels from the dataset
vector<Mat> images;

CascadeClassifier haar_cascade;
haar_cascade.load("/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml");
vector< Rect_<int> > faces;
Mat procFace;
cout << "images: " << preImages.size() << "    labels: " << labels.size() << endl;
for(unsigned int i = 0; i < preImages.size(); i++)
{
    procFace = preImages[i].clone();
    //haar_cascade.detectMultiScale(procFace, faces);
    haar_cascade.detectMultiScale(
            procFace,
            faces,
            1.1,
            3,
            CASCADE_FIND_BIGGEST_OBJECT|CASCADE_DO_ROUGH_SEARCH,
            Size(110, 110)
    );

    if(faces.size() > 0)
    {

        // Process face by face:
        Rect face_i = faces[0];
        // Crop the face from the image.
        Mat face = procFace(face_i);

        ////You can maybe use the equalizeHist function here instead//////
        face = illuminationComp(face);

        //crop face
        Rect cropped(face_i.width*0.18, face_i.height*0.2, int(face_i.width*0.7), int(face_i.height*0.78));
        Mat Cface = face(cropped);

        Mat face_resized;
        resize(Cface, face_resized, Size(128, 128), 1.0, 1.0, INTER_CUBIC);

        images.push_back(face_resized);
    }
}


//svm parameters:
SVMParams params = SVMParams();
params.svm_type = SVM::C_SVC;
params.kernel_type = SVM::LINEAR;
params.degree = 3.43; // for poly
params.gamma = 0.00225; // for poly / rbf / sigmoid
params.coef0 = 19.6; // for poly / sigmoid
params.C = 0.5; // for CV_SVM_C_SVC , CV_SVM_EPS_SVR and CV_SVM_NU_SVR
params.nu = 0.0; // for CV_SVM_NU_SVC , CV_SVM_ONE_CLASS , and CV_SVM_NU_SVR
params.p = 0.0; // for CV_SVM_EPS_SVR
params.class_weights = NULL; // for CV_SVM_C_SVC
params.term_crit.type = CV_TERMCRIT_ITER | CV_TERMCRIT_EPS;
params.term_crit.max_iter = 1000;
params.term_crit.epsilon = 1e-6;

if(images.size() == labels.size())
{
    cout << "Creating SVM Classification" << endl << endl;

    int rowsSize = images.size();
    int trainingArea = images[0].rows * images[0].cols;
    Mat trainingMat = Mat::zeros(rowsSize, trainingArea, CV_32FC1);
    int counter;


    for(int index = 0; index < rowsSize; index++)
    {
        counter = 0;
        for(int rows = 0; rows < images[0].rows; rows++)
        {
            for(int cols = 0; cols < images[0].cols; cols++)
            {
                trainingMat.at<float>(index, counter) = images[index].at<uchar>(rows,cols);
                    counter++;
            }
        }
    }


    Mat matLabels = Mat::zeros(labels.size(),1,CV_32FC1);
    for(size_t index = 0; index < labels.size(); index++)
    {
        matLabels.at<float>(index,0) = float(labels[index]);
    }

    if(trainingMat.rows == matLabels.rows)
    {
        SVM svm;
        svm.train(trainingMat,matLabels,Mat(),Mat(),params);
        svm.save("svm_model.yml");
    }
}

答案 1 :(得分:2)

您似乎正在使用完整的58 * 58面部训练您的SVM。为了使SVM工作,您需要使用已包含在OpenCV中的PCA(主成分分析)等方法来减小维度(获取主要组件)。

如果将尺寸从58 * 58阵列缩小到n * n阵列,其中n是主要特征,则SVM的训练将仅使用主要特征,并将导致改进的解决方案。

OpenCV有很多关于人脸识别的文档,你可以开始here

答案 2 :(得分:0)

我还在构建一个项目,我在其中对一个对象进行分类。我正在使用SVM和Bag of Features(BOf)/ BOW的组合。在这个方法中,首先你创建字典/码本,然后训练你的SVM。结果非常好。

您可以查看此链接以了解http://www.morethantechnical.com/2011/08/25/a-simple-object-classifier-with-bag-of-words-using-opencv-2-3-w-code/