2016-05-09 160 views
1

目前,我正试图训练不同的SVM以识别不同的情绪。因此,例如,要认识到情绪快乐,我训练带有快乐人的图像的支持向量机作为积极和图像,人们表达其他情绪,例如愤怒,恐惧,厌恶......作为否定。这些图像存储在我已经在培训部分和测试部分分区的数据库中。OpenCV 3.1.0:保存并加载训练过的SVM

当我训练完SVM后,我马上用它们来测试数据库测试图像的准确性,这很好。但我也保存训练有素的SVM,因为我想在另一个程序中使用它们,并且不希望每次启动其他程序时都要重新训练它们。

因此,我将SVM加载到其他程序中,但结果非常糟糕。准确度接近0%。所以我试图在训练计划中加载SVM,并且在这里准确度接近零。

搜索了一会儿后,我发现,如果我已经加载了支持向量机和我打印SVM类型,核型和supportvectors,他们是一样的,在SVM .xml文件。所以我认为问题在于预测不能以正确的方式执行。我也不知道我是否保存了我的SVM并以适当的方式加载它们。

目前我已尝试寻找解决方案,但没有任何成功。有的,我已经试过的链接是:

Train SVM and save it with OpenCV 3.0

How to load previously stored svm classifier?

Load Trained SVM – Emgu CV

opencv 3 (C++) auto trained SVM loading issue

,我用它来训练支持向量机,并立即对其进行测试,而无需加载代码他们再次是:

trainData = ml::TrainData::create(training_mat, ROW_SAMPLE, label_mat); 
svm = SVM::create(); 
svm->setType(SVM::C_SVC); 
svm->setKernel(SVM::RBF); 
svm->trainAuto(trainData); 
svm->save(svmSaveNames[i]); 

// Test SVMs 
data_file.open(filenameLabelsTestingImages[i]); 
data_file << "Number\n"; 
startTest = stopTest; 
stopTest = startTest + emotionCountersTesting[i]; 
int numberRightClassified = 0; 
int numberClassified = 0; 

for (int j = 0; j < numberOfTestImg; j++) 
{ 
    cv::Mat testing_one_image_mat(1, numberOfFeatures, CV_32F); 
    for (int k = 0; k < numberOfFeatures; k++) 
    { 
     testing_one_image_mat.at<float>(0, k) = testing_mat.at<float>(j, k); 
    } 

    int value_svm = svmNew->predict(testing_one_image_mat); 

    if (value_svm == 1) 
    { 
     if (j >= startTest && j < stopTest) 
     { 
      numberRightClassified++; 
     } 
     numberClassified++; 
    } 
    data_file << value_svm << endl; 
} 
data_file.close(); 

所以直到我更改代码先保存支持向量机,然后再加载它们的预测如下

trainData = ml::TrainData::create(training_mat, ROW_SAMPLE, label_mat); 
svm = SVM::create(); 
svm->setType(SVM::C_SVC); 
svm->setKernel(SVM::RBF); 
svm->trainAuto(trainData); 
svm->save(svmSaveNames[i]); 

Ptr<SVM> svmNew = SVM::create(); 
svmNew = SVM::load<SVM>(svmSaveNames[i]); 
//cout << "The type is " << svmNew->getType() << endl; 
//cout << "The kernel type is " << svmNew->getKernelType() << endl; 
//cout << "The support vectors are " << svmNew->getSupportVectors() << endl; 

// Test SVMs 
data_file.open(filenameLabelsTestingImages[i]); 
data_file << "Number\n"; 
startTest = stopTest; 
stopTest = startTest + emotionCountersTesting[i]; 
int numberRightClassified = 0; 
int numberClassified = 0; 

for (int j = 0; j < numberOfTestImg; j++) 
{ 
    cv::Mat testing_one_image_mat(1, numberOfFeatures, CV_32F); 
    for (int k = 0; k < numberOfFeatures; k++) 
    { 
     testing_one_image_mat.at<float>(0, k) = testing_mat.at<float>(j, k); 
    } 

    //int value_svm = svm -> predict(testing_one_image_mat); 
    int value_svm = svmNew->predict(testing_one_image_mat); 

    if (value_svm == 1) 
    { 
     if (j >= startTest && j < stopTest) 
     { 
      numberRightClassified++; 
     } 
     numberClassified++; 
    } 
    data_file << value_svm << endl; 
} 
data_file.close(); 

数组svmSaveNames包含名称的字符串保存不同的支持向量机像svm_anger.xml这工作得很好, svm_contempt.xml,...

我使用变量data_file为每个测试的SVM创建一个.txt文件。因此,我首先训练和测试SVM,以识别情绪愤怒,并在测试此SVM时使用所有测试图像。因此,所有这些图像的预测(1 =正/ -1 =负)被写入文本文件。

参数startTest和stopTest用于验证预测值为1的正图像是否在需要识别为正的图像范围内。在数据库的测试地图中,我通过情绪排序所有图像,所以首先愤怒然后蔑视,...

2D矩阵testing_mat包含来自所有测试图像的数据,该数据被提供给SVM以预测情绪。

所以我的问题是,我已经加载SVM后,他们不给我正确的预测。

回答

0

找了一段时间后,我发现如果我使用线性内核,根本没有问题。那么我可以保存并加载SVM,并且预测是正确的。所以我开始寻找它为什么适用于线性内核而不适用于其他内核的原因。

答案是根据Github上的问题#5054在OpenCV 3.1中存在一个错误。我尝试了所提出的解决方案,但它仍然无法工作。最终我重载了OpenCV 2.4,现在一切正常。

+0

你能解释我如何生成svm分类器xml。 –

+0

为了一个很好的解释,你可以检查[使用OpenCV和SVM与图像](http://stackoverflow.com/questions/14694810/using-opencv-and-svm-with-images)。 – Plzzz