Just a Computer Graphics Studio & My Life

[OpenCV] SVM 實驗

剛把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)的距離最大。

程式碼:

/**
	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)

  1. […] 既SVM實驗後,接著實驗高階的SVM。首先還是要瞭解支持向量機器 (Support Vector Machine)和非線性支持向量機器 (Non-linear SVMs),先前的SVM實驗也可以參考。 […]

    喜歡

發表留言

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

標籤雲

%d 位部落客按了讚: