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.羊

你可能感兴趣的:(RM视觉)