Just a Computer Graphics Studio & My Life

[OpenCV] SVM 實驗2

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

怎麼決定超平面(hyperplane)?讓錯誤分類(misclassification)的點距離正確決策區域(correct decision regions)盡可能地小。

程式碼:

/**
	Theme: Support Vector Machines for Non-Linearly Separable Data
	compiler: Visual Studio 2010 with OpenCV 2.4.3
	Date: 101/11/13
	Author: HappyMan
	Blog: https://cg2010studio.wordpress.com/
*/
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp>

#define	NTRAINING_SAMPLES	100			// Number of training samples per class
#define FRAC_LINEAR_SEP		0.7f	    // Fraction of samples which compose the linear separable part

using namespace cv;
using namespace std;

int main(){
    // Data for visual representation
    const int WIDTH = 512, HEIGHT = 512;
    Mat I = Mat::zeros(HEIGHT, WIDTH, CV_8UC3);

    //----- 1. Set up training data randomly
    Mat trainData(2*NTRAINING_SAMPLES, 2, CV_32FC1);
    Mat labels(2*NTRAINING_SAMPLES, 1, CV_32FC1);

    RNG rng(777); // Random value generation class

    //---Set up the linearly separable part of the training data
    int nLinearSamples = (int) (FRAC_LINEAR_SEP * NTRAINING_SAMPLES);

    // Generate random points for the class 1
    Mat trainClass = trainData.rowRange(0, nLinearSamples);
    // The x coordinate of the points is in [0, 0.4)
    Mat c = trainClass.colRange(0, 1);
    rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(0.4 * WIDTH));
    // The y coordinate of the points is in [0, 1)
    c = trainClass.colRange(1,2);
    rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));

    // Generate random points for the class 2
    trainClass = trainData.rowRange(2*NTRAINING_SAMPLES-nLinearSamples, 2*NTRAINING_SAMPLES);
    // The x coordinate of the points is in [0.6, 1]
    c = trainClass.colRange(0 , 1);
    rng.fill(c, RNG::UNIFORM, Scalar(0.6*WIDTH), Scalar(WIDTH));
    // The y coordinate of the points is in [0, 1)
    c = trainClass.colRange(1,2);
    rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));

    //---Set up the non-linearly separable part of the training data

    // Generate random points for the classes 1 and 2
    trainClass = trainData.rowRange(  nLinearSamples, 2*NTRAINING_SAMPLES-nLinearSamples);
    // The x coordinate of the points is in [0.4, 0.6)
    c = trainClass.colRange(0,1);
    rng.fill(c, RNG::UNIFORM, Scalar(0.4*WIDTH), Scalar(0.6*WIDTH));
    // The y coordinate of the points is in [0, 1)
    c = trainClass.colRange(1,2);
    rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));

    //---Set up the labels for the classes
    labels.rowRange(0,   NTRAINING_SAMPLES).setTo(1);  // Class 1
    labels.rowRange(NTRAINING_SAMPLES, 2*NTRAINING_SAMPLES).setTo(2);  // Class 2

    //----- 2. Set up the support vector machines parameters
    CvSVMParams params;
    params.svm_type = SVM::C_SVC;
    params.C = 0.1;
    params.kernel_type = SVM::LINEAR;
    params.term_crit = TermCriteria(CV_TERMCRIT_ITER, (int)1e6, 1e-6);

    //----- 3. Train the svm
    cout << "Starting training process" << endl;
    CvSVM svm;
    svm.train(trainData, labels, Mat(), Mat(), params);
    cout << "Finished training process" << endl;

    //----- 4. Show the decision regions
    Vec3b green(10,100,10), blue (100,10,10);
    for (int i = 0; i < I.rows; ++i)
        for (int j = 0; j < I.cols; ++j){
            Mat sampleMat = (Mat_<float>(1,2) << i, j);
            float response = svm.predict(sampleMat);

            if (response == 1) I.at<Vec3b>(j, i) = green;
            else if (response == 2) I.at<Vec3b>(j, i) = blue;
        }

    //----- 5. Show the training data
    int thick = -1;
    int lineType = 8;
	int radius = 3;
    float px, py;
    // Class 1
    for (int i = 0; i < NTRAINING_SAMPLES; ++i){
        px = trainData.at<float>(i,0);
        py = trainData.at<float>(i,1);
        circle(I, Point( (int) px,  (int) py ), radius, Scalar(0, 255, 0), thick, lineType);
    }
    // Class 2
    for (int i = NTRAINING_SAMPLES; i <2*NTRAINING_SAMPLES; ++i){
        px = trainData.at<float>(i,0);
        py = trainData.at<float>(i,1);
        circle(I, Point( (int) px, (int) py ), radius, Scalar(255, 0, 0), thick, lineType);
    }

    //----- 6. Show support vectors
    thick = 2;
    lineType  = 8;
    int x = svm.get_support_vector_count();

    for (int i = 0; i < x; ++i){
        const float* v = svm.get_support_vector(i);
        circle(	I,  Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thick, lineType);
    }

    imwrite("result.png", I);	                   // save the Image
    imshow("SVM for Non-Linear Training Data", I); // show it to the user
    waitKey(0);
}

執行結果:

亂數種子100,類別樣本數100,正確樣本比例0.9。

亂數種子777,類別樣本數100,正確樣本比例0.9。

亂數種子777,類別樣本數100,正確樣本比例0.7。

亂數種子777,類別樣本數10,正確樣本比例0.7。

還有很多參數可以設定,類別樣本數100時,我跑程式的時間約1分鐘!關鍵在於這一行程式碼:

  • params.term_crit = TermCriteria(CV_TERMCRIT_ITER, (int)1e6, 1e-6);

程式步驟依序:

  1. Set up training data randomly
    1. Set up the linearly separable part of the training data
    2. Set up the non-linearly separable part of the training data
    3. Set up the labels for the classes
  2. Set up the support vector machines parameters
  3. Train the svm
  4. Show the decision regions
  5. Show the training data
  6. Show support vectors

參考:OpenCV v2.4.3 documentation – Support Vector Machines for Non-Linearly Separable Data

Advertisements

發表留言

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

WordPress.com Logo

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

Twitter picture

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

Facebook照片

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

Google+ photo

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

連結到 %s

標籤雲

%d 位部落客按了讚: