2016-05-09 161 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