有关核函数,不想多介绍,参考:https://blog.csdn.net/v_july_v/article/details/7624837
这里简单说明下,以下图二分类为例子,显然线性不可分,我们用核函数 F 将特征向量升维,至三维空间,然后很容易找一个平面将样本分割开来,如图2。
图1
图2
再比如:
1、核函数的分类
(1)线性核函数
(2)多项式核函数
(3)径向基(RBF)核函数(高斯核函数)
(4)Sigmoid核函数(二层神经收集核函数)
2、opencv320 中的核函数定义:
ml::SVM::LINEAR : 线性内核,没有任何向映射至高维空间,线性区分(或回归)在原始特点空间中被完成,这是最快的选择。
.
ml::SVM::POLY : 多项式内核:
.
ml::SVM::RBF : 基于径向的函数,对于大多半景象都是一个较好的选择:
.
ml::SVM::SIGMOID : Sigmoid函数内核:
.
核函数的选用并没有严格数学依据,基本靠经验(基本上就是XJBS)。
例1:识别数字
如图1:我们首先将其进行切割得到5000个样本,利用其80%的样本进行训练,剩余20%作为测试样本。
流程:提取归一化的Hog特征,训练得到xml文件(决策边界参数);预测。
切割程序:
1 #include <opencv2/opencv.hpp> 2 #include <iostream> 3 4 using namespace std; 5 using namespace cv; 6 7 int main() 8 { 9 char ad[128] = { 0 }; 10 int filename = 0, filenum = 0; 11 Mat img = imread("digits.png"); 12 Mat gray; 13 cvtColor(img, gray, CV_BGR2GRAY); 14 int b = 20; 15 int m = gray.rows / b; //原图为1000*2000 16 int n = gray.cols / b; //裁剪为5000个20*20的小图块 17 18 for (int i = 0; i < m; i++) 19 { 20 int offsetRow = i*b; //行上的偏移量 21 if (i % 5 == 0 && i != 0) 22 { 23 filename++; 24 filenum = 0; 25 } 26 for (int j = 0; j < n; j++) 27 { 28 int offsetCol = j*b; //列上的偏移量 29 sprintf_s(ad, "D:\data_svm\%d\%d.jpg", filename, filenum++); 30 // cout << ad << endl; 31 //截取20*20的小块 32 Mat tmp; 33 gray(Range(offsetRow, offsetRow + b), Range(offsetCol, offsetCol + b)).copyTo(tmp); 34 imwrite(ad, tmp); 35 } 36 } 37 return 0; 38 }
切割完之后,图像块保存在如图的文件夹中,每个文件夹中文件索引从0-499
每一张图对应地址下入文本文件:myImageList1.txt 【文中文件见博客最下百度云】
假设拿出每一类中的前400个样本进行当做训练样本;新建一个文本文件 myImageLabels1.txt,写入对应每一类的标签。
最后将测试样本图片路径写入文本文件:myImagetest1.txt
1 //SVM多分类训练测试 2 #include <opencv2/opencv.hpp> 3 #include <iostream> 4 #include <fstream> 5 6 using namespace cv; 7 using namespace std; 8 Size imageSize = Size(64, 64); 9 10 void coumputeHog(const Mat& src, vector<float> &descriptors) 11 { 12 HOGDescriptor myHog = HOGDescriptor(imageSize, Size(16, 16), cvSize(8, 8), cvSize(8, 8), 9); 13 myHog.compute(src.clone(), descriptors, Size(1, 1), Size(0, 0)); 14 15 } 16 17 int main(int argc, char** argv) { 18 ifstream inLabels("myImageLabels1.txt"), inImages("myImageList1.txt"), inTestimage("myImagetest1.txt"); 19 20 string imageName; 21 signed imageLabel; 22 vector<Mat> vecImages; 23 vector<int> vecLabels; 24 //CvSVM *mySVM = new CvSVM(); 25 //CvSVMParams params = CvSVMParams(); 26 //params.svm_type = CvSVM::C_SVC; 27 //params.kernel_type = CvSVM::LINEAR; 28 ////params.kernel_type = CvSVM::RBF; 29 //params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 10000, 1e-10); 30 Ptr<ml::SVM> svm = ml::SVM::create(); 31 svm->setType(ml::SVM::C_SVC); 32 svm->setKernel(ml::SVM::LINEAR); 33 //svm->setDegree(0.5); 34 svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 10000, 1e-10)); 35 36 37 38 vector<float> vecDescriptors; 39 40 #if(1) //是否需要训练 41 while ((inImages >> imageName) && (inLabels >> imageLabel))//读取样本和标签 42 { 43 Mat src = imread(imageName, 0); 44 if (src.empty()) 45 { 46 continue; 47 } 48 resize(src, src, imageSize);//归一化尺寸 49 vecImages.push_back(src);//准备训练样本图序列 50 vecLabels.push_back(imageLabel);//准备图序列对应的标签序列 51 } 52 inLabels.close(); 53 inImages.close(); 54 55 Mat dataDescriptors; 56 Mat dataResponse = (Mat)vecLabels;//还可以这样强制转换? 57 for (size_t i = 0; i < vecImages.size(); i++) 58 { 59 Mat src = vecImages[i];//每一张样本图 60 Mat tempRow; 61 coumputeHog(src, vecDescriptors);//提取Hog特征向量 62 if (i == 0)//这里就是初始化一个 特征矩阵,行数 = 样本数; 每一行存储 每一个样本的Hog特征向量 63 { 64 dataDescriptors = Mat::zeros(vecImages.size(), vecDescriptors.size(), CV_32FC1); 65 } 66 tempRow = ((Mat)vecDescriptors).t();//转置 67 tempRow.row(0).copyTo(dataDescriptors.row(i));//将每一个Hog特征向量保存到特征矩阵中去 68 } 69 70 //mySVM->train(dataDescriptors, dataResponse, Mat(), Mat(), params); 71 svm->train(dataDescriptors, ml::ROW_SAMPLE, dataResponse); 72 //string svmName = to_string(long long(88)) + "_mysvm.xml"; 73 //mySVM->save(svmName.c_str()); 74 svm->save("svm1.xml"); 75 76 //CvSVMParams params = mySVM->get_params(); 77 #else 78 79 //mySVM->load("88_mysvm.xml"); 80 svm = ml::SVM::load("svm1.xml"); 81 #endif 82 83 // 预测 84 string testPath; 85 while (inTestimage >> testPath)//读取每一张测试图 86 { 87 Mat test = imread(testPath, 0); 88 resize(test, test, imageSize);//归一化 89 vector<float> imageDescriptor; 90 coumputeHog(test, imageDescriptor);//提取Hog特征 91 Mat testDescriptor = Mat::zeros(1, imageDescriptor.size(), CV_32FC1);//类型转换 92 for (size_t i = 0; i < imageDescriptor.size(); i++) 93 { 94 testDescriptor.at<float>(0, i) = imageDescriptor[i];//Hog特征赋值 95 } 96 //float label = mySVM->predict(testDescriptor, false);//对当前样本进行 预测 97 // 98 float label = svm->predict(testDescriptor); 99 switch (int(label)) 100 { 101 case 0: 102 cout << label << " " << " = 0" << endl; 103 break; 104 case 1: 105 cout << label << " " << " = 1" << endl; 106 break; 107 case 2: 108 cout << label << " " << " = 2" << endl; 109 break; 110 case 3: 111 cout << label << " " << " = 3" << endl; 112 break; 113 case 4: 114 cout << label << " " << " = 4" << endl; 115 break; 116 case 5: 117 cout << label << " " << " = 5" << endl; 118 break; 119 case 6: 120 cout << label << " " << " = 6" << endl; 121 break; 122 case 7: 123 cout << label << " " << " = 7" << endl; 124 break; 125 case 8: 126 cout << label << " " << " = 8" << endl; 127 break; 128 case 9: 129 cout << label << " " << " = 9" << endl; 130 break; 131 132 } 133 //cout << label << endl; 134 imshow("test image", test); 135 waitKey(0); 136 } 137 138 inTestimage.close(); 139 //delete mySVM; 140 return 0; 141 }
5000个样本训练需要一段时间,工程文件目录下会生成svm1.xml文件。按空格更换样本,打印出预测值。
例2:对飞机、蝴蝶、相机、剪刀、向日葵进行分类。
略,见链接
链接:https://pan.baidu.com/s/1m6JbpGUyDFKfGldfWAYWgg
提取码:xwkx
3、SVM多分类
多分类主要涉及复杂度问题,参考 DAG SVM
链接:https://pan.baidu.com/s/15ItXi0ANQzHS8QaIb6VTkA
提取码:ccqm
复制这段内容后打开百度网盘手机App,操作更方便哦