有關核函數,不想多介紹,參考: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,操作更方便哦