2014-01-24 48 views
4

我試圖使用OpenCV的人臉識別模塊來識別視頻中的2個主題。我從視頻中剪下了第一個主題的30幅面部圖像和第二個主題的20幅面部圖像,並將其用作我的訓練集。如何通過OpenCV人臉識別獲得更好的效果模塊

我已經測試了所有三種方法(特徵臉,Fisherface和LBP直方圖),但在這兩種方法中我都沒有得到好的結果。有時候,第一個主題被分類爲第二個主題和第二個主題,有時虛假檢測被分類爲兩個主題之一,有時視頻中的其他人被分類爲兩個主題之一。

我該如何提高性能?擴大訓練集有助於改善結果嗎?有沒有其他的軟件包可以考慮在C++中執行人臉識別?我認爲這應該是一件容易的事,因爲我試圖認識到只有兩個不同的主題。

這裏是我的代碼,(我用的OpenCV 2.4.7在Windows 8與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); 
} 

由於提前,

吉爾。

+0

擴大訓練集可能會有很大幫助。 – herohuyongtao

+0

謝謝,@herohuyongtao,訓練集應該有多大? – GilLevi

+0

嘗試每個約100個樣本,看看它是如何去。如果它確實有幫助,那麼你的方式是正確的。 – herohuyongtao

回答

10

第一件事情,如評論,如果可能的話,增加樣本的數量。還包括您期望在視頻中的變化(如照明,輕微姿勢等)。但是,特別是對於特徵臉/漁場,如此多的圖像無助於提高性能。可悲的是,最好的訓練樣本數量取決於你的數據。

更重要的一點是問題的硬度完全取決於您的視頻。如果您的視頻包含照明,姿勢等變體,那麼你不能指望純粹基於外觀的方法(例如特徵臉)和紋理描述符(LBP)會成功。首先,你可能想要檢測臉部。然後:

  • 您可能想要估計臉部位置和扭曲到正面;檢查 用於均衡的主動外觀模型和主動形狀模型
  • 使用直方圖以衰減照明問題
  • 擬合橢圓,以檢測到的面部區域將有助於對背景噪聲。

當然,文獻中還有很多其他方法可用;我寫的步驟是在OpenCV中實現的並且通常是已知的。

希望它有幫助。