SVM分类opencv3.0源代码

SVM的理论知识见 SVM的一些总结与认识 –入门级

之前一直以为,用SVM做多分类,不就是用多个SVM分类么,请形状类似于一个二叉树,如下:

即,将所有样本当作输入,其中在训练第一个分类器SVM_1的时候,其正样本为属于类别1的样本,其负样本为剩余的其他所有样本,这就称为 一对其余法,这样做虽然训练的时间从道理上来讲是相对较快的,但是它会带来一系列的问题:

1. 有可能有一个样本在部分分类器 (多于一个,比如2个SVM中,或者更加极端的情况是在所有分类器) 中将其分为正(负)样本,简单的说,就是有不止一个分类器声称它 属于自己,那么便出现错误。相反,如果说,没有一个分类器声称它属于某一个分类器,那么同样出现误分类,

2.一经误分类,则结果误分类。

3.数据集倾斜。这个问题是最影响训练出来的分类器性能的情况,就是说,在训练其中一个训练器的时候,只有某一类作为正样本,其余类别作为负样本,那么导致正 负样本数量出现严重不平衡情况。

其优点明显弱于确定,所以这种情形在实际应用中是不可取的。

第二种方法:一对一

实际应用中,第一种方法得到的模型精度不高,训练时间也同样不占优势。那么这一对一的方法又是怎么回事儿呢?顾名思义:训练多个二分类SVM,也就是任意两个类别训练一个SVM,这样会有一个问题,比如:我有4类样本,按照这种方法多分类的话,需要训练6个SVM,推广到k 个类别则需要k(k-1)/2 个分类器。但他是怎么分类的呢?

简单的说,投票!所有分类器都对这个样本做一个分类(预测),得到的分类结果最多,那么就将这个样本分到这一类。这样做的好处就是,样本怎么样都会有一个预测值,而不会出现无类别的预测结果。目前流行的SVM工具包LIBSVM–台湾大学.Chih-Chung Chung and Chih-Jen Lin就是用的这种方法作为SVM多分类的方法。

第三种方法:DAG SVM

其结构形状如下:

这样分类时,我们可以先问分类器 1v5 (意思是它能回答“是第1类还是第5类”) ,如果回答是5,即往左走,再问“是2还是5”,这样一直问下去,这样做的好处其实是,我们在分类的时候,实际上只是调用了4个分类器。耗时更短,同样不会出现分类重叠或不可分类现象。

现在DAG方法根节点的选取(也就是如何选第一个参与分类的分类器),也有一些方法可以改善整体效果,,我们总希望根节点少犯错误为好,因此参与第一次分类的两个类别,最好是差别特别特别大,大到以至于不太可能把他们分错;或者我们就总取在两类分类中正确率最高的那个分类器作根节点,或者我们让两类分类器在分类的时候,不光输出类别的标签,还输出一个类似“置信度”的东东,当它对自己的结果不太自信的时候,我们就不光按照它的输出走,把它旁边的那条路也走一走,等等。

———————- OpenCV3.0 SVM分类代码 ————-

下面是在OpenCV3.0+Vs2013的平台上(其配置方法见本人另一博文win7平台下vs2013配置OpenCV3.0)的SVM分类代码

#include <opencv2/core.hpp>#include <opencv2/imgproc.hpp>#include "opencv2/imgcodecs.hpp"#include <opencv2/highgui.hpp>#include <opencv2/ml.hpp>using namespace std;using namespace cv;using namespace cv::ml;int main(int, char**){// Data for visual representationint width = 512, height = 512;Mat image = Mat::zeros(height, width, CV_8UC3);// Set up training data//! [setup1]int labels[4] = { 1, -1, -1, 1 };float trainingData[4][2] = { { 1, 2 }, { -1, -10 }, { 1, -2 }, { 2, 1 } };//! [setup1]//! [setup2]Mat trainingDataMat(4, 2, CV_32FC1, trainingData);Mat labelsMat(4, 1, CV_32SC1, labels);//! [setup2]// Train the SVM//! [init]Ptr<SVM> svm = SVM::create();svm->setType(SVM::C_SVC);svm->setKernel(SVM::LINEAR);svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));//! [init]//! [train]svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);//! [train]// Show the decision regions given by the SVM//! [show]Vec3b green(0, 255, 0), blue(255, 0, 0);for (int i = 0; i < image.rows; ++i)for (int j = 0; j < image.cols; ++j){Mat sampleMat = (Mat_<float>(1, 2) << j, i);float response = svm->predict(sampleMat);if (response == 1)image.at<Vec3b>(i, j) = green;else if (response == -1)image.at<Vec3b>(i, j) = blue;}//! [show]// Show the training data//! [show_data]int thickness = -1;int lineType = 8;circle(image, Point(1, 2), 5, Scalar(0, 0, 0), thickness, lineType);circle(image, Point(-1, -10), 5, Scalar(255, 255, 255), thickness, lineType);circle(image, Point(1, -2), 5, Scalar(255, 255, 255), thickness, lineType);circle(image, Point(2, 1), 5, Scalar(255, 255, 255), thickness, lineType);//! [show_data]// Show support vectors//! [show_vectors]thickness = 2;lineType = 8;Mat sv = svm->getSupportVectors();for (int i = 0; i < sv.rows; ++i){const float* v = sv.ptr<float>(i);circle(image, Point((int)v[0], (int)v[1]), 6, Scalar(128, 128, 128), thickness, lineType);}//! [show_vectors]Mat res;float teatData[1][2] = { { 1, -11 } };Mat query(1, 2, CV_32FC1, teatData);svm->predict(query, res);cout << res;imwrite("result.png", image);// save the imageimshow("SVM Simple Example", image); // show it to the userwaitKey(0);}

需要说明的是:在OpenCV中,SVM多分类方式被隐藏参数,在调用函数svm->train() 时,定义函数参数时候,直接输入多类别样本以及其标签即可

既有美妙的风景,也会有称不上景、只有风的地方。

SVM分类opencv3.0源代码

相关文章:

你感兴趣的文章:

标签云: