OpenCV3.0或OpenCV3.1的SVM操作
OpenCV2.0 SVM代碼及其分析
OpenCV 在很久以前就集成了SVM的功能,現(xiàn)在OpenCV升級(jí)到了3.0和3.1了,很多人都不習(xí)慣了怎么調(diào)用OpenCV中的SVM功能了。在之前OpenCV的SVM調(diào)用一直有個(gè)案例:首先,給定幾組訓(xùn)練數(shù)據(jù),并且給了label所對(duì)應(yīng)的值。然后經(jīng)過訓(xùn)練之后,對(duì)圖像的各個(gè)位置進(jìn)行預(yù)測(cè)是1還是-1。如果是1的話,用綠色來表示,如果是-1呢,用藍(lán)色表示。并且還畫出幾個(gè)支持向量。?
下面給了OpenCV2.0 的SVM代碼(勿噴,直接從OpenCV官方網(wǎng)址復(fù)制下來的)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
OpenCV 3.0、OpenCV3.1 的SVM訓(xùn)練代碼
下面給出了正確的,記住是正確的代碼:
例子1:
#include "stdafx.h" #include "opencv2/opencv.hpp" using namespace cv; using namespace cv::ml;int main(int, char**) {int width = 512, height = 512;Mat image = Mat::zeros(height, width, CV_8UC3); //創(chuàng)建窗口可視化// 設(shè)置訓(xùn)練數(shù)據(jù)int labels[10] = { 1, -1, 1, 1,-1,1,-1,1,-1,-1 };Mat labelsMat(10, 1, CV_32SC1, labels);float trainingData[10][2] = { { 501, 150 },{ 255, 10 },{ 501, 255 },{ 10, 501 },{ 25, 80 },{ 150, 300 },{ 77, 200 } ,{ 300, 300 } ,{ 45, 250 } ,{ 200, 200 } };Mat trainingDataMat(10, 2, CV_32FC1, trainingData);// 創(chuàng)建分類器并設(shè)置參數(shù)Ptr<SVM> model = SVM::create();model->setType(SVM::C_SVC);model->setKernel(SVM::LINEAR); //核函數(shù)//設(shè)置訓(xùn)練數(shù)據(jù) Ptr<TrainData> tData = TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);// 訓(xùn)練分類器model->train(tData);Vec3b green(0, 255, 0), blue(255, 0, 0);// 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) << j, i); //生成測(cè)試數(shù)據(jù)float response = model->predict(sampleMat); //進(jìn)行預(yù)測(cè),返回1或-1if (response == 1)image.at<Vec3b>(i, j) = green;else if (response == -1)image.at<Vec3b>(i, j) = blue;}// 顯示訓(xùn)練數(shù)據(jù)int thickness = -1;int lineType = 8;Scalar c1 = Scalar::all(0); //標(biāo)記為1的顯示成黑點(diǎn)Scalar c2 = Scalar::all(255); //標(biāo)記成-1的顯示成白點(diǎn)//繪圖時(shí),先寬后高,對(duì)應(yīng)先列后行for (int i = 0; i < labelsMat.rows; i++){const float* v = trainingDataMat.ptr<float>(i); //取出每行的頭指針Point pt = Point((int)v[0], (int)v[1]);if (labels[i] == 1)circle(image, pt, 5, c1, thickness, lineType);elsecircle(image, pt, 5, c2, thickness, lineType);}imshow("SVM Simple Example", image);waitKey(0);}例子2:
#include "opencv2/opencv.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/highgui.hpp" #include "opencv2/ml.hpp"//using namespace cv; //using namespace cv::ml;int main(int argc, char** argv) {// visual representationint width = 512;int height = 512;cv::Mat image = cv::Mat::zeros(height, width, CV_8UC3);// training dataint labels[4] = { 1, -1, -1, -1 };float trainingData[4][2] = { { 501, 10 }, { 255, 10 }, { 501, 255 }, { 10, 501 } };cv::Mat trainingDataMat(4, 2, CV_32FC1, trainingData);cv::Mat labelsMat(4, 1, CV_32SC1, labels);// initial SVMcv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::create();svm->setType(cv::ml::SVM::Types::C_SVC);svm->setKernel(cv::ml::SVM::KernelTypes::LINEAR);svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER, 100, 1e-6));// train operationsvm->train(trainingDataMat, cv::ml::SampleTypes::ROW_SAMPLE, labelsMat);// predictioncv::Vec3b green(0, 255, 0);cv::Vec3b blue(255, 0, 0);for (int i = 0; i < image.rows; i++){for (int j = 0; j < image.cols; j++){cv::Mat sampleMat = (cv::Mat_<float>(1, 2) << j, i);float respose = svm->predict(sampleMat);if (respose == 1)image.at<cv::Vec3b>(i, j) = green;else if (respose == -1)image.at<cv::Vec3b>(i, j) = blue;}}int thickness = -1;int lineType = cv::LineTypes::LINE_8;cv::circle(image, cv::Point(501, 10), 5, cv::Scalar(0, 0, 0), thickness, lineType);cv::circle(image, cv::Point(255, 10), 5, cv::Scalar(255, 255, 255), thickness, lineType);cv::circle(image, cv::Point(501, 255), 5, cv::Scalar(255, 255, 255), thickness, lineType);cv::circle(image, cv::Point(10, 501), 5, cv::Scalar(255, 255, 255), thickness, lineType);thickness = 2;lineType = cv::LineTypes::LINE_8;cv::Mat sv = svm->getSupportVectors();for (int i = 0; i < sv.rows; i++){const float* v = sv.ptr<float>(i);cv::circle(image, cv::Point((int)v[0], (int)v[1]), 6, cv::Scalar(128, 128, 128), thickness, lineType);}cv::imshow("SVM Simple Example", image);cv::waitKey(0);return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
運(yùn)行的效果如下:?
為了保證代碼可讀性,代碼沒有用using namespace cv或using namespace cv::ml;之類的代碼,全部都寫完整的名稱,命名空間+類名。比如設(shè)置SVM的核類型為線性,寫成svm->setKernel(cv::ml::SVM::KernelTypes::LINEAR);。當(dāng)然,這個(gè)只是一處地方,其他的請(qǐng)自己閱讀。
代碼的注意事項(xiàng)
雖然,大家的目標(biāo)很明確:導(dǎo)入訓(xùn)練數(shù)據(jù)+label –> Mat, 訓(xùn)練,預(yù)測(cè),顯示這些目標(biāo)。但是仍然避免不了代碼錯(cuò)誤。下面就是我遇到的代碼的問題。
標(biāo)簽以及變成Mat的數(shù)據(jù)類型
其實(shí),在本代碼中出現(xiàn)了一種情況就是數(shù)據(jù)類型,下面均以標(biāo)簽為例:?
這個(gè)是OpenCV3.0、OpenCV3.1正確的代碼:
- 1
- 2
下面是OpenCV 2.X 正確代碼
float labels[4] = {1.0, -1.0, -1.0, -1.0}; Mat labelsMat(3, 1, CV_32FC1, labels);- 1
- 2
如果將OpenCV 2.X的代碼換到OpenCV 3.1、OpenCV3.0代碼會(huì)有什么樣子的結(jié)果呢??
?
這個(gè)很熟悉吧所以,如果傻乎乎的換,這個(gè)是行不通的。?
下面對(duì)于label和labelMat按照不同的情況進(jìn)行分析。?
首先,這個(gè)labelMat和trainingMat到底能取哪幾種類型?
下面,請(qǐng)看OpenCV3.1 源碼中的一個(gè)部分:
void setData(InputArray _samples, int _layout, InputArray _responses,InputArray _varIdx, InputArray _sampleIdx, InputArray _sampleWeights,InputArray _varType, InputArray _missing){samples = _samples.getMat(); responses = _responses.getMat();CV_Assert( samples.type() == CV_32F || samples.type() == CV_32S );if( !responses.empty() ){CV_Assert( responses.type() == CV_32F || responses.type() == CV_32S );}}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
為了方便起見,將這個(gè)函數(shù)的代碼的其他部分刪除了。首先解釋一下:samples就是訓(xùn)練的數(shù)據(jù)。response就是標(biāo)簽。通過上面,我們知道再來用Mat的時(shí)候,只能用CV_32F和CV_32S。所以說,如果這些矩陣不能寫什么CV_8UC1之類的了,這個(gè)是錯(cuò)誤的。
假設(shè)我們寫其他的情況,比如
label為int,labelsMat為CV_32SC1
這個(gè)是正確的。
label為float,labelsMat為CV_32FC1
這個(gè)會(huì)出現(xiàn)錯(cuò)誤,這個(gè)我還沒有分析出來是什么原因。錯(cuò)誤的截圖如下:。?
下面的錯(cuò)誤均表示為截圖所示的錯(cuò)誤。
label為int,labelsMat為CV_32FC1
同樣的,這個(gè)是錯(cuò)誤。當(dāng)我們用Imagewatch插件去觀察labelsMat的值的時(shí)候發(fā)現(xiàn)這個(gè)labelsMat的值為。好吧,這個(gè)很明顯了。
label為float,labelsMat為CV_32SC1
這個(gè)是可以運(yùn)行的,但是結(jié)果肯定是錯(cuò)誤的。同樣的,值不對(duì)。
總結(jié)
以上是生活随笔為你收集整理的OpenCV3.0或OpenCV3.1的SVM操作的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C/C++结构体struct 与结构体数
- 下一篇: OpenCV FileStorage类的