Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use SVM for People Recognition?

I'm running opencv 2.4.2 C++.

I'm trying to do people recognition using opencv.

I'm using the VidTIMIT dataset that contains different people in different orientation.

I'm using CvSVM to classify these people.

My problem is that svm's output is always the same.

The algorithm that I follow is:

  1. face detection using Haar
  2. resize of the face (58*58)
  3. Svm Training
  4. Classification

Now, I'm wondering if I did something wrong in the training.

I'm trying this method considering 5(num_name) person, 10(num_images) different images each.

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

The validation code:

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";
}

Hope you can help me.

like image 821
Gappa Avatar asked Nov 02 '12 17:11

Gappa


1 Answers

The other answer here is not correct in saying that SVM must use PCA to function. I have used SVM on 128x128 images without PCA and achieved good results. I have done something similar with the cohn-kanade dataset. Here is some source code that may help out.

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");
    }
}
like image 117
jmo Avatar answered Oct 16 '22 06:10

jmo