opencv7-ml之svm
這部分要特別說明:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html#introductiontosvms或者是《opencv即使是3.0tutorials》中都還是使用的CvSVM::train這樣的函數(shù),但是在對應的《opencv2refman,3.0》中并沒有這個,而是改成了SVM類了,在2.4.10中還是保留的CvSVM的,也就是這里3.0之前和之后得區(qū)別對待一下。
這里還是先介紹CvSVM的版本,畢竟手頭上有2.4.10的,當然也在裝3.0版本的,看著到時候在直接上3.0beta的SVM版本的。下面的都是照搬的,http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html#introductiontosvms。先照搬,然后理解他們 ,接著在加上自己的一些想法
一、svm的介紹? ? 支持向量機 (SVM) 是一個類分類器,正式的定義是一個能夠?qū)⒉煌悩颖驹跇颖究臻g分隔的超平面。 換句話說,給定一些標記(label)好的訓練樣本 (監(jiān)督式學習), SVM算法輸出一個最優(yōu)化的分隔超平面。
如何來界定一個超平面是不是最優(yōu)的呢? 考慮如下問題:假設(shè)給定一些分屬于兩類的2維點,這些點可以通過直線分割, 我們要找到一條最優(yōu)的分割線.
在上面的圖中, 你可以直覺的觀察到有多種可能的直線可以將樣本分開。 那是不是某條直線比其他的更加合適呢? 我們可以憑直覺來定義一條評價直線好壞的標準:距離樣本太近的直線不是最優(yōu)的,因為這樣的直線對噪聲敏感度高,泛化性較差。 因此我們的目標是找到一條直線,離所有點的距離最遠。
由此,SVM算法的實質(zhì)是找出一個能夠?qū)⒛硞€值最大化的超平面(關(guān)于超平面的更加詳細的說明可以參考T. Hastie, R. Tibshirani 和 J. H. Friedman的書籍?Elements of Statistical Learning?, section 4.5 (Seperating Hyperplanes)。),這個值就是超平面離所有訓練樣本的最小距離。這個最小距離用SVM術(shù)語來說叫做?間隔(margin)?。 概括一下,最優(yōu)分割超平面?最大化?訓練數(shù)據(jù)的間隔。
下面的公式定義了超平面的表達式:
?叫做權(quán)重向量,?叫做偏置。最優(yōu)超平面可以有無數(shù)種表達方式,即通過任意的縮放和,習慣上我們使用以下方式來表達最優(yōu)超平面:
式中 x?表示離超平面最近的那些點。 這些點被稱為?支持向量**。 該超平面也稱為 **canonical 超平面.通過幾何學的知識,我們知道點?x?到超平面(,)?的距離為:
特別的,對于 canonical 超平面, 表達式中的分子為1,因此支持向量到canonical 超平面的距離是:
剛才我們介紹了間隔(margin),這里表示為 M?, 它的取值是最近距離的2倍:
最后最大化 M?轉(zhuǎn)化為在附加限制條件下最小化函數(shù)L()?。 限制條件隱含超平面將所有訓練樣本 xi?正確分類的條件,
式中 yi?表示樣本的類別標記。這是一個拉格朗日優(yōu)化問題,可以通過拉格朗日乘數(shù)法得到最優(yōu)超平面的權(quán)重向量?和偏置?。
#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/ml/ml.hpp>using namespace cv;int main() {int width = 512, height = 512;Mat image = Mat::zeros(height, width, CV_8UC3);//生成可顯示結(jié)果的畫布// 建立訓練數(shù)據(jù):標簽及對應數(shù)據(jù)集 而且train中要求是flotat,這里使用四個實參的Mat構(gòu)造函數(shù)的初始化方式。float labels[4] = {1.0, -1.0, -1.0, -1.0};//訓練集合的標簽Mat labelsMat(3, 1, CV_32FC1, labels);//生成矩陣形式,函數(shù)?CvSVM::train?要求訓練數(shù)據(jù)儲存于float類型的?Mat?結(jié)構(gòu)中float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };//訓練集合的數(shù)據(jù)Mat trainingDataMat(3, 2, CV_32FC1, trainingData);//生成矩陣形式,函數(shù)?CvSVM::train?要求訓練數(shù)據(jù)儲存于float類型的?Mat?結(jié)構(gòu)中,即需要的是CV_32FC1類型。// Set up SVM's parameters填充需要的參數(shù)結(jié)構(gòu)CvSVMParams params;params.svm_type = CvSVM::C_SVC;//表示c-支持向量分類,n-類別分類(n>=2);params.kernel_type = CvSVM::LINEAR;//核函數(shù)類型params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);//訓練的時候的終止條件// Train the SVMCvSVM SVM;SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);//訓練svmVec3b green(0,255,0), blue (255,0,0);//初始化兩種顏色來給后面分開的結(jié)果染色// Show the decision regions given by the SVMfor (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);//svm的預測 //下面兩個語句就是進行不同類別使用不同的顏色進行區(qū)分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;circle( image, Point(501, 10), 5, Scalar( 0, 0, 0), thickness, lineType);circle( image, Point(255, 10), 5, Scalar(255, 255, 255), thickness, lineType);circle( image, Point(501, 255), 5, Scalar(255, 255, 255), thickness, lineType);circle( image, Point( 10, 501), 5, Scalar(255, 255, 255), thickness, lineType);// Show support vectors顯示分類面兩邊的支持向量thickness = 2;lineType = 8;int c = SVM.get_support_vector_count();//返回svm的支持向量的個數(shù)//將支持向量畫出來for (int i = 0; i < c; ++i){const float* v = SVM.get_support_vector(i);circle( image, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thickness, lineType);}imwrite("result.png", image); // save the image 保存這幅圖片imshow("SVM Simple Example", image); // show it to the user顯示這幅圖片waitKey(0);}上面的是例子程序,從注釋中就能夠看出,在opencv中訓練一個svm是相當容易和簡單的,不過這是否與封裝的好,還是所支持的內(nèi)容有限有關(guān)就不知道了,不過它是基于libsvm的,不會差,至于libsvm的實現(xiàn)算法,好像聽說新版和舊版的不一樣,不過這都是核心的地方,不了解也沒關(guān)系。
CvSVMParams結(jié)構(gòu)體(在3.0版本的refman中說的是類,雖然在cpp中兩者只有默認權(quán)限的差別,不過還是可以看出3.0更加往著cpp方向?qū)崿F(xiàn)了)
是svm的訓練參數(shù)。該結(jié)構(gòu)必須被初始化并傳遞給CVSVM的訓練方法
構(gòu)造函數(shù)原型:CvSVMParams::CvSVMParams()? ? ? ? ? ? ? ? ? ? ? ? ? ?CvSVMParams::CvSVMParams(int svm_type, int kernel_type, double degree, double gamma, double?coef0, double Cvalue, double nu, double p, CvMat* class_weights,?CvTermCriteria term_crit);
參數(shù):
? ? svm_type:svm公式的類型,可能的值為:
? ? ? ? ? ? ? ? ? ? ?– CvSVM::C_SVC :C-支持向量分類,n-類 分類(n>=2),允許使用懲罰乘數(shù)C對離群點進行不完美分離的懲罰。
? ? ? ? ? ? ? ? ? ? ?– CvSVM::NU_SVC ?:--支持向量分類,有著可能的不完美分離的n-類分類。參數(shù)(范圍為0..1,更大的值表示決策面更加的平滑)用來代替上面的C。
? ? ? ? ? ? ? ? ? ?– CvSVM::ONE_CLASS :分布估計(單類svm)。所有的訓練數(shù)據(jù)都來自于同一個類別,svm構(gòu)建一個邊界用來將這個類與剩下的其他所有訓練數(shù)據(jù)在特征空間中分隔開。
? ? ? ? ? ? ? ? ? ??– CvSVM::EPS_SVR ?:支持向量回歸。介于來自訓練集的特征向量與所擬合的超平面之間的距離必須小于 p 。對于離群點來說,會使用懲罰乘數(shù)C。
? ? ? ? ? ? ? ? ? ? ?– CvSVM::NU_SVR ?:支持向量回歸,用來代替 p。
? ? ? ? ? ? ? ? 見 【libsvm】參考更詳細的說明
? ? kernel_type :svm核函數(shù)類型。可能的值為:
? ? ? ? ? ? ? ? ? ? ? ? ? ?– CvSVM::LINEAR ?線性核函數(shù)。沒有映射操作,只是在最初的特征空間中使用線性決策(或者是回歸)。這是最快的選擇。(當然結(jié)果。。)
? ? ? ? ? ? ? ? ? ? ? ?– CvSVM::POLY ? ? 多項式核函數(shù):
? ? ? ? ? ? ? ? ? ? ??– CvSVM::RBF ? ? ? 徑向基函數(shù),在大多數(shù)情況下都是一個很好的選擇,
? ? ? ? ? ? ? ? ? ? ?– CvSVM::SIGMOID ? sigmoid核函數(shù),
? ? degree ?:核函數(shù)(POLY)的參數(shù)degree;
? ? gamma :核函數(shù)(POLY/RBF/SIGMOID)的參數(shù);
? ? coef0 ? :核函數(shù)(POLY/SIGMOID)的參數(shù)coef0;
? ?Cvalue ?:SVM優(yōu)化問題(C_SVC/EPS_SVR/NU_SVR)的參數(shù)C;
? ? nu ?:SVM優(yōu)化問題(NU_SVC/ONE_CLASS/NU_SVR)的參數(shù);
? ? p ? :SVM優(yōu)化問題(EPS_SVR)的參數(shù);
? ? class_weights :在C_SVC問題中可選的權(quán)重,指定給具體的類別。這樣得到的結(jié)果就是class#i 變成了.所以這些權(quán)重是影響著不同類別的錯誤分類懲罰的程度的。更大的權(quán)值表示在相對的類的錯誤分類數(shù)據(jù)的更大的懲罰。
? ? term_crit :解決受限二次優(yōu)化問題的部分情況下迭代svm訓練過程的終止條件。你可以指定tolerance 和/或者 最大迭代次數(shù)。
該默認構(gòu)造函數(shù)的初始化內(nèi)容是:
CvSVMParams::CvSVMParams() : <span style="white-space:pre"> </span>svm_type(CvSVM::C_SVC), kernel_type(CvSVM::RBF), degree(0), <span style="white-space:pre"> </span>gamma(1), coef0(0), C(1), nu(0), p(0), class_weights(0) { term_crit = cvTermCriteria( CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1000, FLT_EPSILON ); }終止條件結(jié)構(gòu)函數(shù): CV_INLINE CvTermCriteria cvTermCriteria( int type, int max_iter, double epsilon ) {CvTermCriteria t;t.type = type;t.max_iter = max_iter;t.epsilon = (float)epsilon;return t; }該函數(shù)是內(nèi)聯(lián)函數(shù),返回的值為CvTermCriteria結(jié)構(gòu)體。看得出該函數(shù)還是c接口想使用c語言來模擬面向?qū)ο蟮慕Y(jié)構(gòu),其中的參數(shù)為:? ? type:
? ? ? ? ? ? - CV_TERMCRIT_ITER ?在當算法迭代次數(shù)超過max_iter的時候終止。
? ? ? ? ? ? - CV_TERMCRIT_EPS ? 在當算法得到的精度低于epsolon時終止;
? ? ? ? ? ? -CV_TERMCRIT_ITER+CV_TERMCRIT_EPS ?當算法迭代超過max_iter或者當獲得的精度低于epsilon的時候,哪個先滿足就停止。
? ? max_iter:
? ? ? ? ? ? 迭代的最大次數(shù);
? ? epsilon:
? ? ? ? ? ? 要求的精度
svm訓練的函數(shù)原型:bool CvSVM::train(const Mat& trainData, const Mat& responses, const Mat& varIdx=Mat(), const?Mat& sampleIdx=Mat(), CvSVMParams params=CvSVMParams() );
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bool CvSVM::train(const CvMat* trainData, const CvMat* responses, const CvMat* varIdx=0, const?CvMat* sampleIdx=0, CvSVMParams params=CvSVMParams() );
該方法是用來訓練SVM模型的,它與通常的CvStatModel::train()(該函數(shù)為統(tǒng)計模型部分的一個函數(shù),后面的不同分類器訓練函數(shù)都與該函數(shù)類似,這里并沒有仔細介紹該函數(shù),所以下面的參數(shù)暫時沒介紹,下面的約束條件幫助有限,留待我更新統(tǒng)計模型部分的介紹,然后引過來)有著一樣便利的約束條件:
? ? ?a、只有CV_ROW_SAMPLE的數(shù)據(jù)分布才被支持;
? ? ?b、輸入的變量都是有序的
? ? ?c、輸出的變量可以是分類的((params.svm_type=CvSVM::C_SVC 或者?params.svm_type=CvSVM::NU_SVC) 或者有序的(params.svm_type=CvSVM::EPS_SVR 或者?params.svm_type=CvSVM::NU_SVR),或者根本沒要求(params.svm_type=CvSVM::ONE_CLASS)。
?參數(shù)列表:
? ? ?d、不支持缺省的測量方法;
所有的其他參數(shù)都在CvSVMParams結(jié)構(gòu)體中。
svm預測的函數(shù)原型: ?float CvSVM::predict(const Mat& sample, bool returnDFVal=false ) const
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?float CvSVM::predict(const CvMat* sample, bool returnDFVal=false ) const
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??float CvSVM::predict(const CvMat* samples, CvMat* results) const;
參數(shù)列表:
? ? ? ?sample:為了預測的輸入樣本;
? ? ? ?samples:為了預測的輸入的一群樣本;
? ? ? ?returnDFVal :指定返回值的類型。如果為true,而且問題是2分類,那么該方法返回的與邊緣之間有符號距離的決策函數(shù)的值;不然該函數(shù)返回一個類別標簽(分類)或者估計函數(shù)值(回歸)。
? ? ? ?return ?:輸出有關(guān)樣本群的預測響應值。(就是針對許多樣本得到的預測結(jié)果)
如果你傳遞一個樣本那么就得到一個預測結(jié)果。如果你想傳遞幾個樣本那么急救該傳遞給results一個矩陣用來保存預測的結(jié)果。
得到支持向量的個數(shù)和某個支持向量的函數(shù)原型:int CvSVM::get_support_vector_count() const
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const float* CvSVM::get_support_vector(int i) const
參數(shù)列表: i 用來索引某個具體的支持向量。
第一個函數(shù)返回支持向量的個數(shù);第二個可以返回某個支持向量。
贈送一個,返回變量個數(shù)的函數(shù)原型:int CvSVM::get_var_count() const
該函數(shù)返回特征的數(shù)量(也就是變量的個數(shù))
二、支持向量機對線性不可分數(shù)據(jù)的處理
? ?為什么需要將支持向量機優(yōu)化問題擴展到線性不可分的情形? 在多數(shù)計算機視覺運用中,我們需要的不僅僅是一個簡單的SVM線性分類器, 我們需要更加強大的工具來解決?訓練數(shù)據(jù)無法用一個超平面分割?的情形。我們以人臉識別來做一個例子,訓練數(shù)據(jù)包含一組人臉圖像和一組非人臉圖像(除了人臉之外的任何物體)。 這些訓練數(shù)據(jù)超級復雜,以至于為每個樣本找到一個合適的表達 (特征向量) 以讓它們能夠線性分割是非常困難的。
? ?還記得我們用支持向量機來找到一個最優(yōu)超平面。 既然現(xiàn)在訓練數(shù)據(jù)線性不可分,我們必須承認這個最優(yōu)超平面會將一些樣本劃分到錯誤的類別中。 在這種情形下的優(yōu)化問題,需要將?錯分類(misclassification)?當作一個變量來考慮。新的模型需要包含原來線性可分情形下的最優(yōu)化條件,即最大間隔(margin), 以及在線性不可分時分類錯誤最小化。
? ?還是從最大化?間隔?這一條件來推導我們的最優(yōu)化問題的模型(這在上面?已經(jīng)討論了):
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
在這個模型中加入錯分類變量有多種方法。比如,我們可以最小化一個函數(shù),該函數(shù)定義為在原來模型的基礎(chǔ)上再加上一個常量乘以樣本被錯誤分類的次數(shù):
然而,這并不是一個好的解決方案,其中一個原因是它沒有考慮錯分類的樣本距離同類樣本所屬區(qū)域的大小。 因此一個更好的方法是考慮?錯分類樣本離同類區(qū)域的距離:
這里為每一個樣本定義一個新的參數(shù)??, 這個參數(shù)包含對應樣本離同類區(qū)域的距離。 下圖顯示了兩類線性不可分的樣本,以及一個分割超平面和錯分類樣本距離同類區(qū)域的距離。
紅色和藍色直線表示各自區(qū)域的邊際間隔, 每個??表示從錯分類樣本到同類區(qū)域邊際間隔的距離。
最后我們得到最優(yōu)問題的最終模型:
關(guān)于參數(shù)C的選擇, 明顯的取決于訓練樣本的分布情況。 盡管并不存在一個普遍的答案,但是記住下面幾點規(guī)則還是有用的:
? a、C比較大時分類錯誤率較小,但是間隔也較小。 在這種情形下, 錯分類對模型函數(shù)產(chǎn)生較大的影響,既然優(yōu)化的目的是為了最小化這個模型函數(shù),那么錯分類的情形必然會受到抑制。
? b、C比較小時,間隔較大,但是分類錯誤率也較大。在這種情形下,模型函數(shù)中錯分類之和這一項對優(yōu)化過程的影響變小,優(yōu)化過程將更加關(guān)注于尋找到一個能產(chǎn)生較大間隔的超平面。
(這里的兩個例子我都直接復制了完整的代碼,而沒有拆分成重要的函數(shù)說說,就是為了能更加的好理解,拆分成簡單的幾個函數(shù)是為了方便記憶,這里主要還是為了理解。后續(xù)修改3.0版本的時候有可能會刪減!!)
#include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/ml/ml.hpp>#define NTRAINING_SAMPLES 100 // 每個類別中訓練樣本的個數(shù) #define FRAC_LINEAR_SEP 0.9f // 構(gòu)成線性可分樣本的分數(shù),可以當成是為了將int類型轉(zhuǎn)換成float類型的using namespace cv; using namespace std; //該代碼是使用兩個不同的數(shù)據(jù)集來說明的即線性可分的數(shù)據(jù)和非線性可分的數(shù)據(jù)。 int main() {// 創(chuàng)建最后顯示的畫布const int WIDTH = 512, HEIGHT = 512;Mat I = Mat::zeros(HEIGHT, WIDTH, CV_8UC3);//--------------------- 1. 隨機生成訓練數(shù)據(jù) ---------------------------------------Mat trainData(2*NTRAINING_SAMPLES, 2, CV_32FC1);//訓練數(shù)據(jù)為2部分×100個樣本/部分,行表示樣本,列表是變量,即特征Mat labels (2*NTRAINING_SAMPLES, 1, CV_32FC1);//訓練數(shù)據(jù)的標簽RNG rng(100); // 隨機值生成器// 建立數(shù)據(jù)的線性可分部分int nLinearSamples = (int) (FRAC_LINEAR_SEP * NTRAINING_SAMPLES);// class 1 生成隨機樣本Mat trainClass = trainData.rowRange(0, nLinearSamples);//類別1所占用的空間為行[0,nLinearSamples)// x的坐標范圍 [0, 0.4)Mat c = trainClass.colRange(0, 1);//取第一列取值為[a,b)rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(0.4 * WIDTH));//填充數(shù)值// y的坐標范圍 [0, 1)c = trainClass.colRange(1,2);//取第二列rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));//填充數(shù)值// class 2 生成隨機樣本trainClass = trainData.rowRange(2*NTRAINING_SAMPLES-nLinearSamples, 2*NTRAINING_SAMPLES);// x的坐標范圍 [0.6, 1]c = trainClass.colRange(0 , 1); //取第一列rng.fill(c, RNG::UNIFORM, Scalar(0.6*WIDTH), Scalar(WIDTH));//填充數(shù)值// y的坐標范圍 [0, 1)c = trainClass.colRange(1,2);//取第二列rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));//填充數(shù)值//------------------ 為訓練數(shù)據(jù)的第二個部分:線性不可分部分添加數(shù)據(jù) ---------------// 為 classes 1 and 2 隨機生成樣本點trainClass = trainData.rowRange( nLinearSamples, 2*NTRAINING_SAMPLES-nLinearSamples);// x的坐標范圍 [0.4, 0.6)c = trainClass.colRange(0,1);//取第一列rng.fill(c, RNG::UNIFORM, Scalar(0.4*WIDTH), Scalar(0.6*WIDTH)); //填充數(shù)值// y的坐標范圍 [0, 1)c = trainClass.colRange(1,2);//取第二列rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));//填充數(shù)值//------------------------- 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. 設(shè)置SVM的參數(shù) --------------------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)1e7, 1e-6);//------------------------ 3. 訓練SVM ----------------------------------------------------cout << "Starting training process" << endl;CvSVM svm;svm.train(trainData, labels, Mat(), Mat(), params);cout << "Finished training process" << endl;//------------------------ 4. 顯示預測結(jié)果在畫布上 ----------------------------------------Vec3b green(0,100,0), blue (100,0,0);//不同類別的顏色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. 將訓練數(shù)據(jù)顯示在畫布上,使用小圓圈標記------------------------------------int thick = -1;int lineType = 8;float px, py;// Class 1for (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 ), 3, Scalar(0, 255, 0), thick, lineType);}// Class 2for (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 ), 3, Scalar(255, 0, 0), thick, lineType);}//------------------------- 6. 顯示支持向量 --------------------------------------------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 Imageimshow("SVM for Non-Linear Training Data", I); // show it to the userwaitKey(0); } 用隨機數(shù)來填充數(shù)組的函數(shù)原型:void RNG::fill(InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=?false );參數(shù)列表:輸入輸出矩陣、分布類型、第一個分布的參數(shù)、第二個分布參數(shù)、飽和范圍;
第一個參數(shù):2D或者N維矩陣;當前的不支持超過4通道的矩陣,使用Mat::reshape()作為一個可能的解決方案;
第二個參數(shù):分布蕾西,RNG::UNIFORM或者RNG::NORMAL.(即是均勻分布還是正太分布)
第三個參數(shù):第一個分布參數(shù);在均勻分布中,這是一個包含的下限值;在正太分布中,這是一個均值;
第四個參數(shù):第二個分布參數(shù):在均勻分布中,這是一個不包含的上限值;在正太分布中,這是一個標準差(標準差矩陣的對角線或者 ? ? ? ? ? 全標準差矩陣,此處疑問,是兩個矩陣的對角線還是前面那個矩陣的對角線???)。
第五個參數(shù):預飽和標識;只對均勻分布有效;如果該值為true,該方法會首先將a和b轉(zhuǎn)換成可接受的值的范圍(按照mat的數(shù)據(jù)類 ? ? ? ? ? ? ? 型)然后用范圍【saturate(a),saturate(b))來生成均勻分布的隨機值;如果該值為false,該方法會首先按照原 ? ? ? ? 始的范圍【a,b)生成均勻分布隨機值,然后進行飽和操作,也就是說,例如RNG().fill(mat_8u, RNG::UNIFORM, -DBL_MAX, ? ? ? ? ?DBL_MAX),將會生成一個數(shù)組差不多用0和255填滿的數(shù)組,因為范圍(0,255)明顯小于?【-DBL_MAX, DBL_MAX)。
? ?每個使用隨機值來填充矩陣的方法都來自特定的分布。RNG的狀態(tài)也是按照新生成的值更新的。在多通道圖像的情況中,每個通道都是獨立填充的,也就是說RNG不會直接從非對焦協(xié)方差矩陣的多維度高斯分布中采樣。所以該方法是從有著0均值和單一協(xié)方差矩陣的多維度標準高斯分布中進行采樣的,然后接著使用ransform()來轉(zhuǎn)換生成具體的高斯分布的樣本值。
對一個矩陣頭生成具體的行范圍的函數(shù)原型:Mat Mat::rowRange(int startrow, int endrow) const
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Mat Mat::rowRange(const Range& r) const;
參數(shù)列表:
? ? startrow: 一個基于0索引的行范圍的開始,包含
? ? endrow ?:一個基于0索引的行范圍的結(jié)束,不包含
? ? r :Range結(jié)構(gòu),用來包含開始和結(jié)束索引。
對一個矩陣頭生成具體的列范圍的函數(shù)原型:Mat Mat::colRange(int startcol, int endcol) const
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Mat Mat::colRange(const Range& r) const;
參數(shù)列表:?
? ? startrow: 一個基于0索引的列范圍的開始,包含
? ? endrow ?:一個基于0索引的列范圍的結(jié)束,不包含
? ? r :Range結(jié)構(gòu),用來包含開始和結(jié)束索引。
上面兩個方法都是用來對一個新的矩陣頭指定需要生成的行列區(qū)域,相似于Mat::row()和Mat::col(),而且復雜度是O(1).
相對于最上面的終止方法,的類class TermCriteria:
class CV_EXPORTS TermCriteria{ public:enum{ <span style="white-space:pre"> </span>COUNT=1, //!< the maximum number of iterations or elements to compute <span style="white-space:pre"> </span>MAX_ITER=COUNT, //!< ditto <span style="white-space:pre"> </span>EPS=2 //!< the desired accuracy or change in parameters at which the iterative algorithm stops}; //! default constructor <span style="white-space:pre"> </span>TermCriteria(); //! full constructor <span style="white-space:pre"> </span>TermCriteria(int type, int maxCount, double epsilon); //! conversion from CvTermCriteria <span style="white-space:pre"> </span>TermCriteria(const CvTermCriteria& criteria); //! conversion to CvTermCriteria <span style="white-space:pre"> </span>operator CvTermCriteria() const;int type; //!< the type of termination criteria: COUNT, EPS or COUNT + EPS int maxCount; // the maximum number of iterations/elements double epsilon; // the desired accuracy };該類用來為迭代算法定義終止標準。你可以通過默認構(gòu)造函數(shù)進行初始化然后重載任何參數(shù),或者這個結(jié)構(gòu)可以完全使用構(gòu)造函數(shù)的高級變量來全部的初始化。
TermCriteria類的構(gòu)造函數(shù):TermCriteria::TermCriteria()
? ? ? ? ? ? ? ? ? ? ? ? ? TermCriteria::TermCriteria(int type, int maxCount, double epsilon)
? ? ? ? ? ? ? ? ? ? ? ? ? TermCriteria::TermCriteria(const CvTermCriteria& criteria)
參數(shù)列表:
? ? ? ? ?type :終止標準的類型:TermCriteria::COUNT, TermCriteria::EPS 或者?TermCriteria::COUNT + TermCriteria::EPS;
? ? ? ? maxCount:迭代或者計算元素的最大次數(shù);
? ? ? ? epsilon:在迭代算法停止是參數(shù)改變所需要達到的精度要求;
? ? ? ? criteria:在棄用的CvTermCriteria格式中的終止條件。
轉(zhuǎn)換到棄用的CvTermCriteria格式的函數(shù)原型:TermCriteria::operator CvTermCriteria() const (在3.0版本中已經(jīng)移除該函數(shù))
轉(zhuǎn)載于:https://www.cnblogs.com/shouhuxianjian/p/4529174.html
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的opencv7-ml之svm的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【BZOJ1123】 [POI2008]
- 下一篇: discuz_style_default