'SVM實現模式識別(二):支持向量機算法(SVM)(線性多分問題)'

"

支持向量機算法(SVM)(線性多分問題)

1. 技術棧(OPENCV 3.0 +C++)

OpenCV是一個基於BSD許可(開源)發行的跨平臺計算機視覺庫,可以運行在Linux、Windows、Android和Mac OS操作系統上。它輕量級而且高效——由一系列 C 函數和少量 C++ 類構成,同時提供了Python、Ruby、MATLAB等語言的接口,實現了圖像處理和計算機視覺方面的很多通用算法。

OpenCV用C++語言編寫,它的主要接口也是C++語言,但是依然保留了大量的C語言接口。該庫也有大量的Python、Java and MATLAB/OCTAVE(版本2.5)的接口。這些語言的API接口函數可以通過在線文檔獲得。如今也提供對於C#、Ch、Ruby,GO的支持。

"

支持向量機算法(SVM)(線性多分問題)

1. 技術棧(OPENCV 3.0 +C++)

OpenCV是一個基於BSD許可(開源)發行的跨平臺計算機視覺庫,可以運行在Linux、Windows、Android和Mac OS操作系統上。它輕量級而且高效——由一系列 C 函數和少量 C++ 類構成,同時提供了Python、Ruby、MATLAB等語言的接口,實現了圖像處理和計算機視覺方面的很多通用算法。

OpenCV用C++語言編寫,它的主要接口也是C++語言,但是依然保留了大量的C語言接口。該庫也有大量的Python、Java and MATLAB/OCTAVE(版本2.5)的接口。這些語言的API接口函數可以通過在線文檔獲得。如今也提供對於C#、Ch、Ruby,GO的支持。

SVM實現模式識別(二):支持向量機算法(SVM)(線性多分問題)

圖1-2OpenCv

2. 支持向量機SVM算法介紹(OPENCV 3.0 +C++)

支持向量機 (SVM) 是一個類分類器,正式的定義是一個能夠將不同類樣本在樣本空間分隔的超平面。 換句話說,給定一些標記(label)好的訓練樣本 (監督式學習), SVM算法輸出一個最優化的分隔超平面。

如何來界定一個超平面是不是最優的呢? 考慮如下問題:

"

支持向量機算法(SVM)(線性多分問題)

1. 技術棧(OPENCV 3.0 +C++)

OpenCV是一個基於BSD許可(開源)發行的跨平臺計算機視覺庫,可以運行在Linux、Windows、Android和Mac OS操作系統上。它輕量級而且高效——由一系列 C 函數和少量 C++ 類構成,同時提供了Python、Ruby、MATLAB等語言的接口,實現了圖像處理和計算機視覺方面的很多通用算法。

OpenCV用C++語言編寫,它的主要接口也是C++語言,但是依然保留了大量的C語言接口。該庫也有大量的Python、Java and MATLAB/OCTAVE(版本2.5)的接口。這些語言的API接口函數可以通過在線文檔獲得。如今也提供對於C#、Ch、Ruby,GO的支持。

SVM實現模式識別(二):支持向量機算法(SVM)(線性多分問題)

圖1-2OpenCv

2. 支持向量機SVM算法介紹(OPENCV 3.0 +C++)

支持向量機 (SVM) 是一個類分類器,正式的定義是一個能夠將不同類樣本在樣本空間分隔的超平面。 換句話說,給定一些標記(label)好的訓練樣本 (監督式學習), SVM算法輸出一個最優化的分隔超平面。

如何來界定一個超平面是不是最優的呢? 考慮如下問題:

SVM實現模式識別(二):支持向量機算法(SVM)(線性多分問題)

在這個示例中,我們考慮卡迪爾平面內的點與線,而不是高維的向量與超平面。 這一簡化是為了讓我們以更加直覺的方式建立起對SVM概念的理解, 但是其基本的原理同樣適用於更高維的樣本分類情形。

在上面的圖中, 你可以直覺的觀察到有多種可能的直線可以將樣本分開。 那是不是某條直線比其他的更加合適呢? 我們可以憑直覺來定義一條評價直線好壞的標準:距離樣本太近的直線不是最優的,因為這樣的直線對噪聲敏感度高,泛化性較差。 因此我們的目標是找到一條直線,離所有點的距離最遠。

由此, SVM算法的實質是找出一個能夠將某個值最大化的超平面,這個值就是超平面離所有訓練樣本的最小距離。這個最小距離用SVM術語來說叫做 間隔(margin) 。 概括一下,最優分割超平面 最大化 訓練數據的間隔。

"

支持向量機算法(SVM)(線性多分問題)

1. 技術棧(OPENCV 3.0 +C++)

OpenCV是一個基於BSD許可(開源)發行的跨平臺計算機視覺庫,可以運行在Linux、Windows、Android和Mac OS操作系統上。它輕量級而且高效——由一系列 C 函數和少量 C++ 類構成,同時提供了Python、Ruby、MATLAB等語言的接口,實現了圖像處理和計算機視覺方面的很多通用算法。

OpenCV用C++語言編寫,它的主要接口也是C++語言,但是依然保留了大量的C語言接口。該庫也有大量的Python、Java and MATLAB/OCTAVE(版本2.5)的接口。這些語言的API接口函數可以通過在線文檔獲得。如今也提供對於C#、Ch、Ruby,GO的支持。

SVM實現模式識別(二):支持向量機算法(SVM)(線性多分問題)

圖1-2OpenCv

2. 支持向量機SVM算法介紹(OPENCV 3.0 +C++)

支持向量機 (SVM) 是一個類分類器,正式的定義是一個能夠將不同類樣本在樣本空間分隔的超平面。 換句話說,給定一些標記(label)好的訓練樣本 (監督式學習), SVM算法輸出一個最優化的分隔超平面。

如何來界定一個超平面是不是最優的呢? 考慮如下問題:

SVM實現模式識別(二):支持向量機算法(SVM)(線性多分問題)

在這個示例中,我們考慮卡迪爾平面內的點與線,而不是高維的向量與超平面。 這一簡化是為了讓我們以更加直覺的方式建立起對SVM概念的理解, 但是其基本的原理同樣適用於更高維的樣本分類情形。

在上面的圖中, 你可以直覺的觀察到有多種可能的直線可以將樣本分開。 那是不是某條直線比其他的更加合適呢? 我們可以憑直覺來定義一條評價直線好壞的標準:距離樣本太近的直線不是最優的,因為這樣的直線對噪聲敏感度高,泛化性較差。 因此我們的目標是找到一條直線,離所有點的距離最遠。

由此, SVM算法的實質是找出一個能夠將某個值最大化的超平面,這個值就是超平面離所有訓練樣本的最小距離。這個最小距離用SVM術語來說叫做 間隔(margin) 。 概括一下,最優分割超平面 最大化 訓練數據的間隔。

SVM實現模式識別(二):支持向量機算法(SVM)(線性多分問題)

如何計算最優超平面?(感興趣的同學可以自行百度,這裡不做科普。直接用Opencv 算法實現)

3支持向量機SVM算法OPENCV 實現(二分問題)

1建立訓練樣本

本例中的訓練樣本由分屬於兩個類別的2維點組成, 其中一類包含一個樣本點,另一類包含三個點。

\tint labels[4] = { 1, 2, 3, 4 };
\tfloat trainingData[4][2] = { {100, 10}, {10, 500}, {500, 10}, {500, 500} };函數 要求訓練數據儲存於float類型的 結構中, 因此我們定義了以下矩陣:
\tMat trainingDataMat(4, 2, CV_32FC1, trainingData);
\tMat labelsMat (4, 1, CV_32FC1, labels);

2設置SVM參數

```此教程中,我們以可線性分割的分屬兩類的訓練樣本簡單講解了SVM的基本原理。 然而,SVM的實際應用情形可能複雜得多 (比如非線性分割數據問題,SVM核函數的選擇問題等等)。 總而言之,我們需要在訓練之前對SVM做一些參數設定。 這些參數保存在類 CvSVMParams 中。

CvSVMParams params;
params.svm_type = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);

3訓練支持向量機

調用函數 CvSVM::train 來建立SVM模型。

\tCvSVM SVM;
\tSVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);

4 SVM區域分割

函數 CvSVM::predict 通過重建訓練完畢的支持向量機來將輸入的樣本分類。 本例中我們通過該函數給向量空間著色, 及將圖像中的每個像素當作卡迪爾平面上的一點,每一點的著色取決於SVM對該點的分類類別:綠色表示標記為1的點,藍色表示標記為-1的點。

Vec3b green(0, 255, 0), blue(255, 0, 0), red(0, 0, 255), yellow(0, 255, 255);
for (int i = 0; i < image.rows; ++i) {
for (int j = 0; j < image.cols; ++j) {
Mat sampleMat = (Mat_<float>(1, 2) << j, i);
float response = svm->predict(sampleMat);
double ratio = 0.5;
if (response == 1)
image.at<Vec3b>(i, j) = green * ratio;
else if (response == 2)
image.at<Vec3b>(i, j) = blue * ratio;
else if (response == 3) {
image.at<Vec3b>(i, j) = red * ratio;
}
else if (response == 4) {
image.at<Vec3b>(i, j) = yellow * ratio;
}
}
}

5.支持向量

這裡用了幾個函數來獲取支持向量的信息。 函數 CvSVM::get_support_vector_count 輸出支持向量的數量,函數 CvSVM::get_support_vector 根據輸入支持向量的索引來獲取指定位置的支持向量。 通過這一方法我們找到訓練樣本的支持向量並突出顯示它們。

Mat sv = svm->getSupportVectors();
std::cout << sv << std::endl;
for (int i = 0; i < sv.rows; ++i) {
const float* v = sv.ptr<float>(i);
circle(image, Point((int)v[0], (int)v[1]), 6, CV_RGB(128, 128, 128), 2);
}

結果

"

支持向量機算法(SVM)(線性多分問題)

1. 技術棧(OPENCV 3.0 +C++)

OpenCV是一個基於BSD許可(開源)發行的跨平臺計算機視覺庫,可以運行在Linux、Windows、Android和Mac OS操作系統上。它輕量級而且高效——由一系列 C 函數和少量 C++ 類構成,同時提供了Python、Ruby、MATLAB等語言的接口,實現了圖像處理和計算機視覺方面的很多通用算法。

OpenCV用C++語言編寫,它的主要接口也是C++語言,但是依然保留了大量的C語言接口。該庫也有大量的Python、Java and MATLAB/OCTAVE(版本2.5)的接口。這些語言的API接口函數可以通過在線文檔獲得。如今也提供對於C#、Ch、Ruby,GO的支持。

SVM實現模式識別(二):支持向量機算法(SVM)(線性多分問題)

圖1-2OpenCv

2. 支持向量機SVM算法介紹(OPENCV 3.0 +C++)

支持向量機 (SVM) 是一個類分類器,正式的定義是一個能夠將不同類樣本在樣本空間分隔的超平面。 換句話說,給定一些標記(label)好的訓練樣本 (監督式學習), SVM算法輸出一個最優化的分隔超平面。

如何來界定一個超平面是不是最優的呢? 考慮如下問題:

SVM實現模式識別(二):支持向量機算法(SVM)(線性多分問題)

在這個示例中,我們考慮卡迪爾平面內的點與線,而不是高維的向量與超平面。 這一簡化是為了讓我們以更加直覺的方式建立起對SVM概念的理解, 但是其基本的原理同樣適用於更高維的樣本分類情形。

在上面的圖中, 你可以直覺的觀察到有多種可能的直線可以將樣本分開。 那是不是某條直線比其他的更加合適呢? 我們可以憑直覺來定義一條評價直線好壞的標準:距離樣本太近的直線不是最優的,因為這樣的直線對噪聲敏感度高,泛化性較差。 因此我們的目標是找到一條直線,離所有點的距離最遠。

由此, SVM算法的實質是找出一個能夠將某個值最大化的超平面,這個值就是超平面離所有訓練樣本的最小距離。這個最小距離用SVM術語來說叫做 間隔(margin) 。 概括一下,最優分割超平面 最大化 訓練數據的間隔。

SVM實現模式識別(二):支持向量機算法(SVM)(線性多分問題)

如何計算最優超平面?(感興趣的同學可以自行百度,這裡不做科普。直接用Opencv 算法實現)

3支持向量機SVM算法OPENCV 實現(二分問題)

1建立訓練樣本

本例中的訓練樣本由分屬於兩個類別的2維點組成, 其中一類包含一個樣本點,另一類包含三個點。

\tint labels[4] = { 1, 2, 3, 4 };
\tfloat trainingData[4][2] = { {100, 10}, {10, 500}, {500, 10}, {500, 500} };函數 要求訓練數據儲存於float類型的 結構中, 因此我們定義了以下矩陣:
\tMat trainingDataMat(4, 2, CV_32FC1, trainingData);
\tMat labelsMat (4, 1, CV_32FC1, labels);

2設置SVM參數

```此教程中,我們以可線性分割的分屬兩類的訓練樣本簡單講解了SVM的基本原理。 然而,SVM的實際應用情形可能複雜得多 (比如非線性分割數據問題,SVM核函數的選擇問題等等)。 總而言之,我們需要在訓練之前對SVM做一些參數設定。 這些參數保存在類 CvSVMParams 中。

CvSVMParams params;
params.svm_type = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);

3訓練支持向量機

調用函數 CvSVM::train 來建立SVM模型。

\tCvSVM SVM;
\tSVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);

4 SVM區域分割

函數 CvSVM::predict 通過重建訓練完畢的支持向量機來將輸入的樣本分類。 本例中我們通過該函數給向量空間著色, 及將圖像中的每個像素當作卡迪爾平面上的一點,每一點的著色取決於SVM對該點的分類類別:綠色表示標記為1的點,藍色表示標記為-1的點。

Vec3b green(0, 255, 0), blue(255, 0, 0), red(0, 0, 255), yellow(0, 255, 255);
for (int i = 0; i < image.rows; ++i) {
for (int j = 0; j < image.cols; ++j) {
Mat sampleMat = (Mat_<float>(1, 2) << j, i);
float response = svm->predict(sampleMat);
double ratio = 0.5;
if (response == 1)
image.at<Vec3b>(i, j) = green * ratio;
else if (response == 2)
image.at<Vec3b>(i, j) = blue * ratio;
else if (response == 3) {
image.at<Vec3b>(i, j) = red * ratio;
}
else if (response == 4) {
image.at<Vec3b>(i, j) = yellow * ratio;
}
}
}

5.支持向量

這裡用了幾個函數來獲取支持向量的信息。 函數 CvSVM::get_support_vector_count 輸出支持向量的數量,函數 CvSVM::get_support_vector 根據輸入支持向量的索引來獲取指定位置的支持向量。 通過這一方法我們找到訓練樣本的支持向量並突出顯示它們。

Mat sv = svm->getSupportVectors();
std::cout << sv << std::endl;
for (int i = 0; i < sv.rows; ++i) {
const float* v = sv.ptr<float>(i);
circle(image, Point((int)v[0], (int)v[1]), 6, CV_RGB(128, 128, 128), 2);
}

結果

SVM實現模式識別(二):支持向量機算法(SVM)(線性多分問題)

源碼:

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include "opencv2/imgcodecs.hpp"
#include <opencv2/highgui.hpp>
#include <opencv2/ml.hpp>
using namespace cv;
using namespace cv::ml;
Vec3b getRandomColor() {
RNG rng(clock());
return Vec3b(rng.next() % 255, rng.next() % 255, rng.next() % 255);
}
int main(int, char**)
{
// Data for visual representation
int width = 512, height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);
// Set up training data
int labels[4] = { 1, 2, 3, 4 };
float trainingData[4][2] = { {100, 10}, {10, 500}, {500, 10}, {500, 500} };
Mat trainingDataMat(4, 2, CV_32FC1, trainingData);
Mat labelsMat(4, 1, CV_32SC1, labels);
// Train the SVM
//! [init]
Ptr<SVM> svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::POLY);
svm->setDegree(1.0);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
//! [init]
//! [train]
// svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);
// Ptr<TrainData> auto_train_data = TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);
// svm->trainAuto(auto_train_data);
svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);
//! [train]
// Show the decision regions given by the SVM
//! [show]
Vec3b green(0, 255, 0), blue(255, 0, 0), red(0, 0, 255), yellow(0, 255, 255);
for (int i = 0; i < image.rows; ++i) {
for (int j = 0; j < image.cols; ++j) {
Mat sampleMat = (Mat_<float>(1, 2) << j, i);
float response = svm->predict(sampleMat);
double ratio = 0.5;
if (response == 1)
image.at<Vec3b>(i, j) = green * ratio;
else if (response == 2)
image.at<Vec3b>(i, j) = blue * ratio;
else if (response == 3) {
image.at<Vec3b>(i, j) = red * ratio;
}
else if (response == 4) {
image.at<Vec3b>(i, j) = yellow * ratio;
}
}
}
int thickness = -1;
int lineType = 8;
circle(image, Point(100, 10), 5, Scalar(0, 255, 0), thickness, lineType);
circle(image, Point(10, 500), 5, Scalar(255, 0, 0), thickness, lineType);
circle(image, Point(500, 10), 5, Scalar(0, 0, 255), thickness, lineType);
circle(image, Point(500, 500), 5, Scalar(0, 255, 255), thickness, lineType);
thickness = 2;
lineType = 8;
Mat sv = svm->getSupportVectors();
std::cout << sv << std::endl;
for (int i = 0; i < sv.rows; ++i) {
const float* v = sv.ptr<float>(i);
circle(image, Point((int)v[0], (int)v[1]), 6, CV_RGB(128, 128, 128), 2);
}
imwrite("result.png", image); // save the image
imshow("SVM Simple Example", image); // show it to the user
waitKey(0);
}

注意:

32 位系統中,int 整數佔 4 個字節,指針同樣佔 4 個字節

64 位系統中,int 整數佔 4 個字節,指針同樣佔 8 個字節

"

相關推薦

推薦中...