剛把OpenCV更新到2.4.3版,來試驗一下它的SVM好不好用。首先當然要瞭解支持向量機器 (Support Vector Machine)和非線性支持向量機器 (Non-linear SVMs),先前的SVM實驗也可以參考。
支持向量機(Support Vector Machine, SVM)是一種監督式學習的方法,一般是應用於分類(Classification/supervised learning)等相關議題上。SVM 基本運作模式如下:在給定一群訓練樣本之下,每個樣本會分別對應至兩個不同的類別(Category),SVM 會嘗試從建構一個模型(Model),並利用此模型將每一個樣本分配到一個類別上。
典型的SVM是一種二元分類器(Two-class classifier),因此,先針對典型SVM來進行說明。
在二元分類中,SVM嘗試在訓練資料(training data)所構成的空間中,尋找一個超平面(hyperplane)能將不同類別的資料完美的分開,而且,希望此超平面與不同的類別的距離愈大愈好。如圖所示,藍色圓形為第一個類別(標記為+1),紅色方形為第二個類別(標記為-1),而SVM則想要找出的超平面即是wx+b=0,此超平面可以使得兩個類別(class)的距離最大。
- 環境設定:Visual Studio 2010 安裝 OpenCV 2.4
- 範例程式:C:\OpenCV2.4.3\samples\cpp\tutorial_code\ml\introduction_to_svm\introduction_to_svm.cpp
程式碼:
/** Theme: Introduction to Support Vector Machines compiler: Visual Studio 2010 with OpenCV 2.4.3 Date: 101/11/12 Author: HappyMan Blog: https://cg2010studio.wordpress.com/ */ #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/ml/ml.hpp> using namespace cv; int main() { // Data for visual representation int width = 512, height = 512; Mat image = Mat::zeros(height, width, CV_8UC3); // Set up training data float labels[4] = {1.0, -1.0, -1.0, -1.0}; Mat labelsMat(4, 1, CV_32FC1, labels); Point point1 = Point(501.0, 100.0); Point point2 = Point(255.0, 100.0); Point point3 = Point(501.0, 255.0); Point point4 = Point(100.0, 501.0); float trainingData[4][2] = { {point1.x, point1.y}, {point2.x, point2.y}, {point3.x, point3.y}, {point4.x, point4.y} }; Mat trainingDataMat(4, 2, CV_32FC1, trainingData); // Set up SVM's parameters CvSVMParams params; params.svm_type = CvSVM::C_SVC; params.kernel_type = CvSVM::LINEAR; params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6); // Train the SVM CvSVM SVM; SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params); Vec3b green(100,255,100), blue(255,100,100); // Show the decision regions given by the SVM for (int i = 0; i < image.rows; ++i) for (int j = 0; j < image.cols; ++j) { Mat sampleMat = (Mat_<float>(1,2) << i,j); float response = SVM.predict(sampleMat); if (response == 1) image.at<Vec3b>(j, i) = green; else if (response == -1) image.at<Vec3b>(j, i) = blue; } // Show the training data int thickness = -1; int lineType = 8; int radius = 3; circle(image, point1, radius, labels[0]==1.0?Scalar(0,0,0):Scalar(255, 255, 255), thickness, lineType); circle(image, point2, radius, labels[1]==1.0?Scalar(0,0,):Scalar(255, 255, 255), thickness, lineType); circle(image, point3, radius, labels[2]==1.0?Scalar(0,0,0):Scalar(255, 255, 255), thickness, lineType); circle(image, point4, radius, labels[3]==1.0?Scalar(0,0,0):Scalar(255, 255, 255), thickness, lineType); // Show support vectors thickness = 2; lineType = 8;radius = 6; int count = SVM.get_support_vector_count(); for (int i = 0; i < count; ++i) { const float* vector = SVM.get_support_vector(i); circle( image, Point( (int) vector[0], (int) vector[1]), radius, Scalar(128, 128, 128), thickness, lineType); } // save the image imwrite("result.png", image); // show it to the user imshow("SVM HappyMan Example", image); waitKey(0); }
執行結果:
此圖分類得相當完美!
改變標籤:
- float labels[4] = {-1.0, 1.0, 1.0, -1.0};
然而此圖無法分類,該怎麼辦?剛好範例顏色不是藍就是綠,該站哪一邊比較好呢:P?
參考:OpenCV v2.4.3 documentation – Introduction to Support Vector Machines、WiKi – 支持向量機、支援向量機(Support Vector Machine, SVM)之多重分類。
Comments on: "[OpenCV] SVM 實驗" (1)
[…] 既SVM實驗後,接著實驗高階的SVM。首先還是要瞭解支持向量機器 (Support Vector Machine)和非線性支持向量機器 (Non-linear SVMs),先前的SVM實驗也可以參考。 […]
讚讚