opencv——基於SVM的數字識別(1)
阿新 • • 發佈:2019-01-13
關於SVM的原理有很多優秀的視訊和資料,這裡我主要說下利用SVM對數字識別的具體應用
首先,需要有數字的訓練樣本
https://download.csdn.net/download/weixin_41721222/10784418
把0-9資料夾放入模版匹配樣本之中,自己可修改。
核心思路:
1:獲取一張訓練圖片後會將圖片特徵寫入到容器中,緊接著會將標籤寫入另一個容器中,這樣就保證了特徵和標籤是一一對應的關係。
2:特徵可用LBP,HOG等提取,但是我們這裡主要說SVM訓練過程,所以用最簡單的方法,即把訓練圖片的全部畫素序列成一行畫素作為特徵,用reshape(1,1)。
3:圖片特徵資料得轉換成CV_32FC1的資料格式。
下面程式碼是opencv3和C++
可以根據自己需要修改訓練樣本類別,數目,尺寸。oss的訓練樣本路徑,src的檢測圖片路徑。
#include <stdio.h> #include <time.h> #include <opencv2/opencv.hpp> #include <opencv/cv.h> #include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/ml/ml.hpp> #include <io.h> //查詢檔案相關函式 using namespace std; using namespace cv; using namespace ml; ostringstream oss; int num = -1; Mat dealimage; Mat src; Mat yangben_gray; Mat yangben_thresh; int main() { //核心思路://獲取一張圖片後會將圖片特徵寫入到容器中, //緊接著會將標籤寫入另一個容器中,這樣就保證了特徵 // 和標籤是一一對應的關係。 ////===============================讀取訓練資料===============================//// const int classsum = 10;//圖片共有10類,可修改 const int imagesSum = 500;//每類有張圖片,可修改 //訓了樣本圖片與測試圖片的尺寸應該一樣 const int imageRows = 20;//圖片尺寸 const int imageCols = 20; //訓練資料,每一行一個訓練圖片 Mat trainingData; //訓練樣本標籤 Mat labels; //最終的訓練樣本標籤 Mat clas; //最終的訓練資料 Mat traindata; //////////////////////從指定資料夾下提取圖片////////////////// for (int p = 0; p < classsum; p++)//依次提取0到9資料夾中的圖片 { oss << "C:/Users/zhang/Desktop/opencv——例項/小案例/車牌檢測/基於adaboost機器學習/模版匹配樣本/"; num += 1;//num從0到9 int label = num; oss << num << "/*.jpg";//圖片名字字尾,oss可以結合數字與字串 string pattern = oss.str();//oss.str()輸出oss字串,並且賦給pattern oss.str("");//每次迴圈後把oss字串清空 vector<Mat> input_images; vector<String> input_images_name; glob(pattern, input_images_name, false); //為false時,僅僅遍歷指定資料夾內符合模式的檔案,當為true時,會同時遍歷指定資料夾的子資料夾 //此時input_images_name存放符合條件的圖片地址 int all_num = input_images_name.size(); //檔案下總共有幾個圖片 //cout << num << ":總共有" << all_num << "個圖片待測試" << endl; for (int i = 0; i < imagesSum; i++)//依次迴圈遍歷每個資料夾中的圖片 { cvtColor(imread(input_images_name[i]), yangben_gray, COLOR_BGR2GRAY);//灰度變換 threshold(yangben_gray, yangben_thresh, 0, 255, THRESH_OTSU);//二值化 //迴圈讀取每張圖片並且依次放在vector<Mat> input_images內 input_images.push_back(yangben_thresh); dealimage = input_images[i]; //注意:我們簡單粗暴將整個圖的所有畫素作為了特徵,因為我們關注更多的是整個的訓練過程 //,所以選擇了最簡單的方式完成特徵提取工作,除此中外, //特徵提取的方式有很多,比如LBP,HOG等等 //我們利用reshape()函式完成特徵提取, //eshape(1, 1)的結果就是原影象對應的矩陣將被拉伸成一個一行的向量,作為特徵向量。 dealimage = dealimage.reshape(1, 1);//圖片序列化 trainingData.push_back(dealimage);//序列化後的圖片依次存入 labels.push_back(label);//把每個圖片對應的標籤依次存入 } } //圖片資料和標籤轉變下 Mat(trainingData).copyTo(traindata);//複製 traindata.convertTo(traindata, CV_32FC1);//更改圖片資料的型別,必要,不然會出錯 Mat(labels).copyTo(clas);//複製 ////===============================建立SVM模型===============================//// // 建立分類器並設定引數 Ptr<SVM> SVM_params = SVM::create(); SVM_params->setType(SVM::C_SVC);//C_SVC用於分類,C_SVR用於迴歸 SVM_params->setKernel(SVM::LINEAR); //LINEAR線性核函式。SIGMOID為高斯核函式 SVM_params->setDegree(0);//核函式中的引數degree,針對多項式核函式; SVM_params->setGamma(1);//核函式中的引數gamma,針對多項式/RBF/SIGMOID核函式; SVM_params->setCoef0(0);//核函式中的引數,針對多項式/SIGMOID核函式; SVM_params->setC(1);//SVM最優問題引數,設定C-SVC,EPS_SVR和NU_SVR的引數; SVM_params->setNu(0);//SVM最優問題引數,設定NU_SVC, ONE_CLASS 和NU_SVR的引數; SVM_params->setP(0);//SVM最優問題引數,設定EPS_SVR 中損失函式p的值. //結束條件,即訓練1000次或者誤差小於0.01結束 SVM_params->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 0.01)); //訓練資料和標籤的結合 Ptr<TrainData> tData = TrainData::create(traindata, ROW_SAMPLE, clas); // 訓練分類器 SVM_params->train(tData);//訓練 //儲存模型 //SVM_params->save("C:/Users/zhang/Desktop/opencv——例項/小案例/車牌檢測/基於adaboost機器學習/字元識別svm.xml"); cout << "訓練好了!!!" << endl; ////===============================預測部分===============================//// Mat src = imread("C:/Users/zhang/Desktop/opencv——例項/小案例/車牌檢測/基於adaboost機器學習/檢測到的車牌字元/7.jpg"); cvtColor(src, src, COLOR_BGR2GRAY); threshold(src, src, 0, 255, CV_THRESH_OTSU); imshow("原影象", src); Mat input; src = src.reshape(1, 1);//輸入圖片序列化 input.push_back(src); input.convertTo(input, CV_32FC1);//更改圖片資料的型別,必要,不然會出錯 float r = SVM_params->predict(input); //對所有行進行預測 cout << r << endl; waitKey(0); return 0; }
識別結果: