C++ Opencv Hog+svm 二分類
阿新 • • 發佈:2018-12-20
// opencv3 #include <stdio.h> #include <iostream> #include <fstream> #include <opencv2/opencv.hpp> #include <string> using namespace cv::ml; #define PosSamNO 30 //正樣本個數 #define NegSamNO 30 //負樣本個數 #define TestSamNO 5 //測試個數 void train_svm_hog() { //HOG檢測器,用來計算HOG描述子的 //檢測視窗(48,48),塊尺寸(16,16),塊步長(8,8),cell尺寸(8,8),直方圖bin個數9 cv::HOGDescriptor hog(cv::Size(48, 48), cv::Size(16, 16), cv::Size(8, 8), cv::Size(8, 8), 9); int DescriptorDim;//HOG描述子的維數,由圖片大小、檢測視窗大小、塊大小、細胞單元中直方圖bin個數決定 //設定SVM引數 cv::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)); std::string ImgName; //正樣本圖片的檔案列表 std::ifstream finPos("positive_samples.txt"); //負樣本圖片的檔案列表 std::ifstream finNeg("negative_samples.txt"); //所有訓練樣本的特徵向量組成的矩陣,行數等於所有樣本的個數,列數等於HOG描述子維數 cv::Mat sampleFeatureMat; //訓練樣本的類別向量,行數等於所有樣本的個數,列數等於1;1表示有目標,-1表示無目標 cv::Mat sampleLabelMat; //依次讀取正樣本圖片,生成HOG描述子 for (int num = 0; num < PosSamNO && getline(finPos, ImgName); num++) { std::cout << "Processing:" << ImgName << std::endl; cv::Mat image = cv::imread(ImgName); cv::resize(image, image, cv::Size(48, 48)); //HOG描述子向量 std::vector<float> descriptors; //計算HOG描述子,檢測視窗移動步長(8,8) hog.compute(image, descriptors, cv::Size(8, 8)); //處理第一個樣本時初始化特徵向量矩陣和類別矩陣,因為只有知道了特徵向量的維數才能初始化特徵向量矩陣 if (0 == num) { //HOG描述子的維數 DescriptorDim = descriptors.size(); //初始化所有訓練樣本的特徵向量組成的矩陣,行數等於所有樣本的個數,列數等於HOG描述子維數sampleFeatureMat sampleFeatureMat = cv::Mat::zeros(PosSamNO + NegSamNO, DescriptorDim, CV_32FC1); //初始化訓練樣本的類別向量,行數等於所有樣本的個數,列數等於1 sampleLabelMat = cv::Mat::zeros(PosSamNO + NegSamNO, 1, CV_32SC1); } //將計算好的HOG描述子複製到樣本特徵矩陣sampleFeatureMat for (int i = 0; i < DescriptorDim; i++) { //第num個樣本的特徵向量中的第i個元素 sampleFeatureMat.at<float>(num, i) = descriptors[i]; } //正樣本類別為1,判別為無噴濺 sampleLabelMat.at<float>(num, 0) = 1; } //依次讀取負樣本圖片,生成HOG描述子 for (int num = 0; num < NegSamNO && getline(finNeg, ImgName); num++) { std::cout << "Processing:" << ImgName << std::endl; cv::Mat src = cv::imread(ImgName); cv::resize(src, src, cv::Size(48, 48)); //HOG描述子向量 std::vector<float> descriptors; //計算HOG描述子,檢測視窗移動步長(8,8) hog.compute(src, descriptors, cv::Size(8, 8)); //處理第一個樣本時初始化特徵向量矩陣和類別矩陣,因為只有知道了特徵向量的維數才能初始化特徵向量矩陣 //std::cout << "descriptor dimention:" << descriptors.size() << std::endl; //將計算好的HOG描述子複製到樣本特徵矩陣sampleFeatureMat for (int i = 0; i < DescriptorDim; i++) { //第PosSamNO+num個樣本的特徵向量中的第i個元素 sampleFeatureMat.at<float>(num + PosSamNO, i) = descriptors[i]; } //負樣本類別為-1,判別為噴濺 sampleLabelMat.at<float>(num + PosSamNO, 0) = -1; } //訓練SVM分類器 std::cout << "開始訓練SVM分類器" << std::endl; cv::Ptr<cv::ml::TrainData> td = cv::ml::TrainData::create(sampleFeatureMat, cv::ml::SampleTypes::ROW_SAMPLE, sampleLabelMat); svm->train(td); std::cout << "SVM分類器訓練完成" << std::endl; //將訓練好的SVM模型儲存為xml檔案 svm->save("SVM_HOG.xml"); return; } void svm_hog_classification() { //HOG檢測器,用來計算HOG描述子的 //檢測視窗(48,48),塊尺寸(16,16),塊步長(8,8),cell尺寸(8,8),直方圖bin個數9 cv::HOGDescriptor hog(cv::Size(48, 48), cv::Size(16, 16), cv::Size(8, 8), cv::Size(8, 8), 9); //HOG描述子的維數,由圖片大小、檢測視窗大小、塊大小、細胞單元中直方圖bin個數決定 int DescriptorDim; //測試樣本圖片的檔案列表 std::ifstream finTest("test_samples.txt"); std::string ImgName; for (int num = 0; num < TestSamNO && getline(finTest, ImgName); num++) { //從XML檔案讀取訓練好的SVM模型 cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::load<cv::ml::SVM>("SVM_HOG.xml "); if (svm->empty()) { std::cout << "load svm detector failed!!!" << std::endl; return; } //針對測試集進行識別 std::cout << "開始識別..." << std::endl; std::cout << "Processing:" << ImgName << std::endl; cv::Mat test = cv::imread(ImgName); cv::resize(test, test, cv::Size(48, 48)); std::vector<float> descriptors; hog.compute(test, descriptors); cv::Mat testDescriptor = cv::Mat::zeros(1, descriptors.size(), CV_32FC1); for (size_t i = 0; i < descriptors.size(); i++) { testDescriptor.at<float>(0, i) = descriptors[i]; } float label = svm->predict(testDescriptor); imshow("test image", test); std::cout << "這張圖屬於:" << label << std::endl; cv::waitKey(0); } return; } int main(int argc, char** argv) { train_svm_hog(); svm_hog_classification(); return 0; }