RoboMaster_SWPU鐵人戰隊視覺組工作筆記(二)在opencv3以上中遇到的SVM坑

一、前言

  之前做視覺工程的時候,用的是opencv2.4.9,成功用上了SVM做幾何體分類,但自從opencv3對SVM的調用方法大改後,套用之前的工程就遇到了很多問題,爲了給以後的人正確的指引,也爲了給自己提個醒,便有了寫下這篇博文的心。正文開始之前,不妨聽我絮叨一下。
  鐵人戰隊自RM第一次比賽之初創立已有5年曆史,最近學校批准我們可以參加RM2020賽季機甲大師賽,大家興奮不已。之前哭着喊着要參加RM,終於有機會參賽了,但真正落到自己頭上的時候,還是有諸多問題,隊員資質、比賽資金、老師支持、隊伍人心、規則大改都是問題,我才意識到長路漫漫,其修遠兮。這一年對我們來說是機會也是難題,難在隊伍招新不達標,人員配置有很大問題,好在規則大改,意味着所有隊伍都沒有經驗,我們更能成爲一匹黑馬,大殺四方。未來還有更多的年輕人來到鐵人戰隊,有望學以成才,活出不一樣的人生,甚至看着今天我們鐵人戰隊的榮耀,爲自己是鐵人戰隊的一員而感到驕傲、自豪。我們有着責任,有着義務,排除一切艱難險阻,爲了心中的白月光,熱血奮鬥到2020賽季結束。總之,一起加油吧,青年工程師們。

二、在opencv3.0.0中遇到的SVM坑

1、設置SVM類型,內核類型,迭代終止條件時,參數設置按網上某篇教程有錯,下面的代碼裏面是正確的設置方法。
2、使用trainAuto時,參數不能直接給(訓練數據,類型,標籤),要以TrainData類對象的形式給定。
3、標籤的類型必須是CV_32S,不能是CV_32F。
4、標籤不能是負數,即不能給負樣本設置標籤爲-1。
5、訓練數據最好不要用push_back的形式給定,會錯行,而用range方式給定,則不會錯行,我用debug看過二者矩陣大小的區別,用push_back會多個30多行,另外這樣拿去作爲創建TrainData的參數會報錯。
6、內核類型選用RBF(徑向基核)還沒有LINEAR(線性內核)好用,同樣的訓練數據,選用RBF會出現很多誤判,大坑啊,誰說的用RBF能處理大部分情況的,打死。

下面是我測試過的opencv3.0.0 SVM識別裝甲板數字的工程代碼,僅作爲參考用。

#include "./SVM_TrainAuto/svm_trainauto.h"

using namespace std;
using namespace cv;

int main()
{
    // initial SVM
   Ptr<ml::SVM> _svmClassifier = ml::SVM::create();
   _svmClassifier->setType(ml::SVM::C_SVC);   //SVM類型(允許用異常值懲罰因子C進行不完全分類)
   _svmClassifier->setKernel(ml::SVM::LINEAR);  //SVM的內核類型,一般情況下使用徑向基核可以很好處理大部分情況
   _svmClassifier->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 10000, 1e-6)); //指定迭代終止的條件

   RM::MySVM mySVM;
   printf("\t\t\t\t開始獲取訓練集數據\n");
   mySVM.getTrainData();
   printf("\t\t\t\t成功獲取訓練集數據\n");
   printf("\t\t\t\tSVM訓練樣本開始\n");
   //SVM的訓練函數是ROW_SAMPLE類型的,也就是說,送入SVM訓練的特徵需要reshape成一個行向量,所有訓練數據全部保存在一個Mat中,一個訓練樣本就是Mat中的一行
   Ptr<ml::TrainData> tData = ml::TrainData::create(mySVM._trainData, ml::ROW_SAMPLE, mySVM._trainClasses);
   _svmClassifier->trainAuto(tData);//自動訓練並優化參數
   _svmClassifier->save("svm.xml");
   printf("\t\t\t\tSVM訓練樣本結束\n");

   Mat srcImg = imread(ARMOR_IMAGE_PATH,IMREAD_COLOR);
   Mat grayImg,imageNewSize;
   cvtColor(srcImg,grayImg,COLOR_BGR2GRAY);
   resize(grayImg, imageNewSize, Size(mySVM._sampleData.width,mySVM._sampleData.height)); //統一攝像頭畫面裏面採集到的輪廓圖像的尺寸
   grayImg.release();					   //把image的矩陣信息釋放(清除)
   grayImg = imageNewSize.reshape(0, 1);   //圖像深度不變,把圖片矩陣轉爲一行儲存
   grayImg.convertTo(grayImg, CV_32FC1);
   int response = (int)_svmClassifier->predict(grayImg);

   switch (response)
   {
       case RM::Hero:
          putText(srcImg,mySVM._sampleData.str,Point(srcImg.size().width/2,srcImg.size().height/2),
                  FONT_HERSHEY_SIMPLEX,0.5,Scalar(0, 0, 255));
          break;

       default : break;
   }
   imshow("【效果圖】",srcImg);
   waitKey(0);

   return 0;
}

SVM模型訓練好後,opencv3.0.0加載模型用如下語句:

Ptr<ml::SVM> _svmClassifier = ml::SVM::load<ml::SVM>("svm.xml");

-------------------------------------------------------更新-----------------------------------------------------------
opencv3.4.6加載模型用如下語句:

Ptr<ml::SVM> _svmClassifier = ml::StatModel::load<ml::SVM>("svm.xml");

opencv3.4.6不支持圖像顯示窗格名有中文格式

如支持    imshow("_roiImg",_roiImg);
不支持    imshow("【原始圖像】",_roiImg);

識別到的效果圖如下:
在這裏插入圖片描述

本期作者:Young
csdn暱稱:Mr.羊
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章