OpenCV3.0或OpenCV3.1的SVM操作
OpenCV2.0 SVM代碼及其分析
OpenCV 在很久以前就集成了SVM的功能,現在OpenCV升級到了3.0和3.1了,很多人都不習慣了怎么調用OpenCV中的SVM功能了。在之前OpenCV的SVM調用一直有個案例:首先,給定幾組訓練數據,并且給了label所對應的值。然后經過訓練之后,對圖像的各個位置進行預測是1還是-1。如果是1的話,用綠色來表示,如果是-1呢,用藍色表示。并且還畫出幾個支持向量。?
下面給了OpenCV2.0 的SVM代碼(勿噴,直接從OpenCV官方網址復制下來的)
- 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訓練代碼
下面給出了正確的,記住是正確的代碼:
例子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); //創建窗口可視化// 設置訓練數據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);// 創建分類器并設置參數Ptr<SVM> model = SVM::create();model->setType(SVM::C_SVC);model->setKernel(SVM::LINEAR); //核函數//設置訓練數據 Ptr<TrainData> tData = TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);// 訓練分類器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); //生成測試數據float response = model->predict(sampleMat); //進行預測,返回1或-1if (response == 1)image.at<Vec3b>(i, j) = green;else if (response == -1)image.at<Vec3b>(i, j) = blue;}// 顯示訓練數據int thickness = -1;int lineType = 8;Scalar c1 = Scalar::all(0); //標記為1的顯示成黑點Scalar c2 = Scalar::all(255); //標記成-1的顯示成白點//繪圖時,先寬后高,對應先列后行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
運行的效果如下:?
為了保證代碼可讀性,代碼沒有用using namespace cv或using namespace cv::ml;之類的代碼,全部都寫完整的名稱,命名空間+類名。比如設置SVM的核類型為線性,寫成svm->setKernel(cv::ml::SVM::KernelTypes::LINEAR);。當然,這個只是一處地方,其他的請自己閱讀。
代碼的注意事項
雖然,大家的目標很明確:導入訓練數據+label –> Mat, 訓練,預測,顯示這些目標。但是仍然避免不了代碼錯誤。下面就是我遇到的代碼的問題。
標簽以及變成Mat的數據類型
其實,在本代碼中出現了一種情況就是數據類型,下面均以標簽為例:?
這個是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代碼會有什么樣子的結果呢??
?
這個很熟悉吧所以,如果傻乎乎的換,這個是行不通的。?
下面對于label和labelMat按照不同的情況進行分析。?
首先,這個labelMat和trainingMat到底能取哪幾種類型?
下面,請看OpenCV3.1 源碼中的一個部分:
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
為了方便起見,將這個函數的代碼的其他部分刪除了。首先解釋一下:samples就是訓練的數據。response就是標簽。通過上面,我們知道再來用Mat的時候,只能用CV_32F和CV_32S。所以說,如果這些矩陣不能寫什么CV_8UC1之類的了,這個是錯誤的。
假設我們寫其他的情況,比如
label為int,labelsMat為CV_32SC1
這個是正確的。
label為float,labelsMat為CV_32FC1
這個會出現錯誤,這個我還沒有分析出來是什么原因。錯誤的截圖如下:。?
下面的錯誤均表示為截圖所示的錯誤。
label為int,labelsMat為CV_32FC1
同樣的,這個是錯誤。當我們用Imagewatch插件去觀察labelsMat的值的時候發現這個labelsMat的值為。好吧,這個很明顯了。
label為float,labelsMat為CV_32SC1
這個是可以運行的,但是結果肯定是錯誤的。同樣的,值不對。
總結
以上是生活随笔為你收集整理的OpenCV3.0或OpenCV3.1的SVM操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C/C++结构体struct 与结构体数
- 下一篇: OpenCV FileStorage类的