【机器学习】LBP+SVM实现特征检测
生活随笔
收集整理的這篇文章主要介紹了
【机器学习】LBP+SVM实现特征检测
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
初學機器學習,參考HOG SVM 車輛檢測(https://www.cnblogs.com/louyihang-loves-baiyan/p/4658478.html)、LBP特征原理(https://blog.csdn.net/q1007729991/article/details/52995734)及LBP特征的實現及LBP+SVM分類 (https://blog.csdn.net/qianqing13579/article/details/49406563)的一些理論知識內容,實現基于LBP特征加上其他約束特征,結合SVM模型訓練正負樣本,實現二分類、對感興趣特征的檢測。
#include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/gpu/gpu.hpp> #include<opencv2/ml/ml.hpp> #include<opencv2/objdetect/objdetect.hpp> #include<iostream> #include<fstream> #include<string> #include<vector>using namespace cv; using namespace std;#define TRAIN //開關控制是否訓練還是直接載入訓練好的模型class MySVM: public CvSVM { public:double * get_alpha_data(){return this->decision_func->alpha;}double get_rho_data(){return this->decision_func->rho;} };//計算輸入圖片的最大灰度差、平均灰度、平均梯度 int calAverageGary(const Mat &inImg, int &maxGaryDiff, int &averageGrad_xy) {float averageGary;int garySum = 0;int i, j;//求平均灰度值for (i=0; i<inImg.cols; i++){for (j=0; j<inImg.rows; j++){garySum += inImg.at<uchar>(j, i);}}averageGary = (int)(garySum*1.0f/(inImg.rows*inImg.cols));//求滑窗內的最大灰度差值double minGary, maxGary; minMaxLoc(inImg, &minGary, &maxGary, NULL, NULL);maxGaryDiff = (int)(maxGary-minGary);//求滑窗內的平均梯度值Mat grad_x, grad_y, abs_grad_x, abs_grad_y, grad_xy; Sobel( inImg, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT ); //求X方向梯度 convertScaleAbs( grad_x, abs_grad_x ); Sobel( inImg, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT ); //求Y方向梯度 convertScaleAbs( grad_y, abs_grad_y ); addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad_xy); //合并梯度(近似) //cout<<"gary_xy"<<grad_xy<<endl;int grad_xy_sum = 0;for (i=0; i<inImg.cols; i++){for (j=0; j<inImg.rows; j++){grad_xy_sum += grad_xy.at<uchar>(j, i);}}averageGrad_xy = (int)(grad_xy_sum*1.0f/(inImg.rows*inImg.cols));return averageGary; }// 計算等價模式LBP特征圖 static void ComputeLBPImage_Uniform(const Mat &srcImage, Mat &LBPImage) {// 參數檢查,內存分配CV_Assert(srcImage.depth() == CV_8U&&srcImage.channels() == 1);LBPImage.create(srcImage.size(), srcImage.type());// 計算LBP圖Mat extendedImage;copyMakeBorder(srcImage, extendedImage, 1, 1, 1, 1, BORDER_DEFAULT);// LUT(256種每一種模式對應的等價模式)static const int table[256] = { 1, 2, 3, 4, 5, 0, 6, 7, 8, 0, 0, 0, 9, 0, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 14, 0, 15, 16, 17, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25,0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 27, 0, 28, 29, 30, 31, 0, 32, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 36, 37, 38, 0, 39, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 43, 44, 0, 45, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 47, 48, 49, 0, 50, 0, 0, 0, 51, 52, 53, 0, 54, 55, 56, 57, 58 };// 計算LBPint heightOfExtendedImage = extendedImage.rows;int widthOfExtendedImage = extendedImage.cols;int widthOfLBP=LBPImage.cols;uchar *rowOfExtendedImage = extendedImage.data+widthOfExtendedImage+1;uchar *rowOfLBPImage = LBPImage.data;int pixelDiff = 5;for (int y = 1; y <= heightOfExtendedImage - 2; ++y,rowOfExtendedImage += widthOfExtendedImage, rowOfLBPImage += widthOfLBP){// 列uchar *colOfExtendedImage = rowOfExtendedImage;uchar *colOfLBPImage = rowOfLBPImage;for (int x = 1; x <= widthOfExtendedImage - 2; ++x, ++colOfExtendedImage, ++colOfLBPImage){// 計算LBP值int LBPValue = 0;if (colOfExtendedImage[0 - widthOfExtendedImage - 1] >= colOfExtendedImage[0]+pixelDiff)LBPValue += 128;if (colOfExtendedImage[0 - widthOfExtendedImage] >= colOfExtendedImage[0]+pixelDiff)LBPValue += 64;if (colOfExtendedImage[0 - widthOfExtendedImage + 1] >= colOfExtendedImage[0]+pixelDiff)LBPValue += 32;if (colOfExtendedImage[0 + 1] >= colOfExtendedImage[0]+pixelDiff)LBPValue += 16;if (colOfExtendedImage[0 + widthOfExtendedImage + 1] >= colOfExtendedImage[0]+pixelDiff)LBPValue += 8;if (colOfExtendedImage[0 + widthOfExtendedImage] >= colOfExtendedImage[0]+pixelDiff)LBPValue += 4;if (colOfExtendedImage[0 + widthOfExtendedImage - 1] >= colOfExtendedImage[0]+pixelDiff)LBPValue += 2;if (colOfExtendedImage[0 - 1] >= colOfExtendedImage[0]+pixelDiff)LBPValue += 1;colOfLBPImage[0] = table[LBPValue];}} }//計算歸一化的LBP特征矩陣 static void ComputeLBPFeatureVector_Uniform(const Mat &srcImage, Size cellSize, Mat &featureVector) {// 參數檢查,內存分配CV_Assert(srcImage.depth() == CV_8U&&srcImage.channels() == 1);Mat LBPImage;ComputeLBPImage_Uniform(srcImage, LBPImage);//cout<<"LBPImage_uniform:"<<endl<<LBPImage<<endl<<endl;// 計算cell個數int widthOfCell = cellSize.width;int heightOfCell = cellSize.height;int numberOfCell_X = srcImage.cols / widthOfCell;// X方向cell的個數int numberOfCell_Y = srcImage.rows / heightOfCell;// 特征向量的個數int numberOfDimension = 58 * numberOfCell_X*numberOfCell_Y;featureVector.create(1, numberOfDimension, CV_32FC1);featureVector.setTo(Scalar(0));// 計算LBP特征向量int stepOfCell=srcImage.cols;int index = -58;// cell的特征向量在最終特征向量中的起始位置float *dataOfFeatureVector=(float *)featureVector.data;for (int y = 0; y <= numberOfCell_Y - 1; ++y){for (int x = 0; x <= numberOfCell_X - 1; ++x){index+=58;// 計算每個cell的LBP直方圖Mat cell = LBPImage(Rect(x * widthOfCell, y * heightOfCell, widthOfCell, heightOfCell));uchar *rowOfCell=cell.data;int sum = 0; // 每個cell的等價模式總數for(int y_Cell=0;y_Cell<=cell.rows-1;++y_Cell,rowOfCell+=stepOfCell){uchar *colOfCell=rowOfCell;for(int x_Cell=0;x_Cell<=cell.cols-1;++x_Cell,++colOfCell){if(colOfCell[0]!=0){// 在直方圖中轉化為0~57,所以是colOfCell[0] - 1++dataOfFeatureVector[index + colOfCell[0]-1];++sum;}}}for (int i = 0; i <= 57; ++i)dataOfFeatureVector[index + i] /= sum;}} }//計算擴展LBP特征矩陣,在原LBP特征上增加了3維 void calExtendLBPFeature(const Mat &srcImage, Size cellSize, Mat &extendLBPFeature) {// 參數檢查,內存分配CV_Assert(srcImage.depth() == CV_8U&&srcImage.channels() == 1);Mat LBPImage;int i,j, height, width;height = srcImage.rows;width = srcImage.cols;ComputeLBPFeatureVector_Uniform(srcImage, cellSize, LBPImage); //求歸一化后的LBP特征//cout<<"LBPImage"<<LBPImage<<endl; //取值范圍[0,58]//把LBPImage折算到[0,255]之間Mat LBPImage_255(1, LBPImage.cols, CV_8UC1, Scalar(0));for (i=0; i<LBPImage.cols; i++){LBPImage_255.at<uchar>(0,i) = (uchar)(LBPImage.at<float>(0,i) * 255.0f);}//cout<<"LBPImage_255"<<endl<<LBPImage_255<<endl;int maxGaryDiff, averageGrad_xy;int averageGary = calAverageGary(srcImage, maxGaryDiff, averageGrad_xy);//cout<<"averageGary="<<averageGary<<", maxGrayDiff="<<maxGaryDiff<<endl<<endl;int descriptorDim;descriptorDim = LBPImage.cols + 3;Mat extendLBPFeature_255 = Mat::zeros(1, descriptorDim, CV_8UC1); for (i=0; i<LBPImage.cols; i++){extendLBPFeature_255.at<uchar>(0,i) = LBPImage_255.at<uchar>(0,i);}extendLBPFeature_255.at<uchar>(0,LBPImage.cols) = averageGary; //增加維度,存放平均像素extendLBPFeature_255.at<uchar>(0,LBPImage.cols+1) = maxGaryDiff; //增加維度,存放最大灰度差extendLBPFeature_255.at<uchar>(0,LBPImage.cols+2) = averageGrad_xy; //增加維度,存放平均梯度//把擴展LBP特征矩陣歸一化extendLBPFeature = Mat(1, descriptorDim, CV_32FC1, Scalar(0)); for(i=0; i<descriptorDim; i++){extendLBPFeature.at<float>(0,i) = extendLBPFeature_255.at<uchar>(0,i)*1.0f/255;}//cout<<"extendLBPFeature: "<<endl<<extendLBPFeature<<endl; }int main(int argc, char ** argv) {MySVM SVM;int descriptorDim;string buffer;string trainImg;vector<string> posSamples;vector<string> negSamples;vector<string> testSamples;int posSampleNum;int negSampleNum;int testSampleNum;double rho;#ifdef TRAIN //此開關開啟,使用正負樣本進行訓練ifstream fInPos("..\\Inputs\\PositiveSample.txt"); //讀取正樣本ifstream fInNeg("..\\Inputs\\NegtiveSample.txt"); //讀取負樣本while (fInPos) //正樣本讀入imgPathList中{if(getline(fInPos, buffer))posSamples.push_back(buffer);}posSampleNum = posSamples.size();fInPos.close();while(fInNeg) //讀取負樣本{if (getline(fInNeg, buffer))negSamples.push_back(buffer);}negSampleNum = negSamples.size();fInNeg.close();Mat sampleFeatureMat; //樣本特征向量矩陣Mat sampleLabelMat; //樣本標簽//1、處理正樣本for(int i = 0 ; i < posSampleNum; i++) {Mat inputImg = imread(posSamples[i]);GaussianBlur(inputImg, inputImg, Size(3,3), 0);cout<<"processing "<<i<<"/"<<posSampleNum<<" "<<posSamples[i]<<endl;Size dsize = Size(12,30);Mat trainImg = Mat(dsize, CV_8UC1);resize(inputImg, trainImg, dsize);if (trainImg.channels()>1) cvtColor(trainImg, trainImg, CV_BGR2GRAY);Mat dstImg(trainImg.rows, trainImg.cols, CV_8UC1, Scalar(0));vector<int> descriptor;//等價模式LBP特征計算Mat sigleFeatureMat;calExtendLBPFeature(trainImg, Size(3, 3), sigleFeatureMat);descriptorDim = sigleFeatureMat.cols;if(i == 0)//首次特殊處理根據檢測到的維數確定特征矩陣的尺寸{sampleFeatureMat = Mat::zeros(posSampleNum + negSampleNum, descriptorDim, CV_32FC1);sampleLabelMat = Mat::zeros(posSampleNum + negSampleNum, 1, CV_32SC1);}sigleFeatureMat.row(0).copyTo(sampleFeatureMat.row(i)); //把sigleFeatureMat的第一列賦給sampleFeatureMat的第i列sampleLabelMat.at<int>(i, 0) = 1;}cout<<"extract posSampleFeature done"<<endl; //2、處理負樣本for(int i = 0 ; i < negSampleNum; i++){Mat inputImg = imread(negSamples[i]);GaussianBlur(inputImg, inputImg, Size(3,3), 0);cout<<"processing "<<i<<"/"<<negSampleNum<<" "<<negSamples[i]<<endl;Size dsize = Size(12,30);Mat trainImg = Mat(dsize, CV_8UC1);resize(inputImg, trainImg, dsize);if (trainImg.channels()>1) cvtColor(trainImg, trainImg, CV_BGR2GRAY);Mat dstImg(trainImg.rows, trainImg.cols, CV_8UC1, Scalar(0));Mat sigleFeatureMat; //單行矩陣//12×30負樣本,等價模式LBP特征計算(增加3維)calExtendLBPFeature(trainImg, Size(3, 3), sigleFeatureMat);sigleFeatureMat.row(0).copyTo(sampleFeatureMat.row(posSampleNum + i)); //把sigleFeatureMat賦給sampleFeatureMat的第i列sampleLabelMat.at<int>(posSampleNum + i, 0) = 0; //標簽保存樣本被劃分的類型}cout<<"extract negSampleFeature done"<<endl; ofstream foutFeature("SampleLBPFeatureMat.txt"); //保存特征向量文件for(int i = 0; i < posSampleNum + negSampleNum; i++){for(int j = 0; j < descriptorDim; j++){foutFeature<<sampleFeatureMat.at<float>(i, j)<<" ";}foutFeature<<"\n";}foutFeature.close();cout<<"output posSample and negSample Feature done"<<endl; CvTermCriteria criteria = cvTermCriteria(CV_TERMCRIT_ITER, 1000, FLT_EPSILON);CvSVMParams params(CvSVM::C_SVC, CvSVM::LINEAR, 0, 0.5, 0, 0.01, 0, 0, 0, criteria); cout<<"SVM Training Start..."<<endl;SVM.train_auto(sampleFeatureMat, sampleLabelMat, Mat(), Mat(), params);SVM.save("SVM_Model.xml");cout<<"SVM Training Complete"<<endl; #endif //TRAIN#ifndef TRAIN //沒定義TRAIN,直接使用訓練好的模型SVM.load("SVM_Model.xml");//加載模型文件 #endifdescriptorDim = SVM.get_var_count();int supportVectorNum = SVM.get_support_vector_count();cout<<"support vector num: "<< supportVectorNum <<endl;Mat alphaMat = Mat::zeros(1, supportVectorNum, CV_32FC1);Mat supportVectorMat = Mat::zeros(supportVectorNum, descriptorDim, CV_32FC1);Mat resultMat = Mat::zeros(1, descriptorDim, CV_32FC1);for (int i = 0; i < supportVectorNum; i++) //復制支持向量矩陣{const float * pSupportVectorData = SVM.get_support_vector(i);for(int j = 0 ;j < descriptorDim; j++){supportVectorMat.at<float>(i,j) = pSupportVectorData[j];}}double *pAlphaData = SVM.get_alpha_data();for (int i = 0; i < supportVectorNum; i++) //復制函數中的alpha 記住決策公式Y= wx+b{alphaMat.at<float>(0, i) = pAlphaData[i];}resultMat = -1 * alphaMat * supportVectorMat; //alphaMat就是權重向量cout<<"描述子維數 "<<descriptorDim<<endl;vector<float> myDetector;for (int i = 0 ;i < descriptorDim; i++){myDetector.push_back(resultMat.at<float>(0, i));}rho = SVM.get_rho_data();myDetector.push_back(rho);cout<<"檢測子維數 "<<myDetector.size()<<endl;//保存檢測子int minusNum = 0;int posNum = 0;ofstream foutDetector("HogDetectorForCarFace.txt");for (int i = 0 ;i < myDetector.size(); i++){foutDetector<<myDetector[i]<<" "; //cout<<myDetector[i]<<" ";}//cout<<endl<<"posNum "<<posNum<<endl;//cout<<endl<<"minusNum "<<minusNum<<endl;foutDetector.close();//測試部分ifstream fInTest("..\\Inputs\\testSample.txt"); //加載測試樣本while (fInTest){if(getline(fInTest, buffer)){testSamples.push_back( buffer);}}testSampleNum = testSamples.size();fInTest.close(); VideoWriter outputVideo;char saveNameExt[1200], dispParams[1200];sprintf(saveNameExt, "..\\Demo.avi");outputVideo.open(saveNameExt, CV_FOURCC('M','P','4','2'),10,Size(300, 720),true); //保存處理結果成視頻for (int i = 0; i < testSamples.size(); i++){Mat testImg = imread(testSamples[i]);if(testImg.empty()) return -1;if(testImg.channels()>1) cvtColor(testImg, testImg, CV_BGR2GRAY);imshow("原圖", testImg);GaussianBlur(testImg, testImg, Size(3,3), 0); //高斯濾波//imshow("高斯濾波后", testImg);//equalizeHist(testImg, testImg); //直方圖均衡//imshow("直方圖均衡后", testImg);Mat copyImg = testImg.clone();if(copyImg.channels()<3) cvtColor(copyImg, copyImg, CV_GRAY2BGR);Mat testImgNorm; resize(testImg, testImgNorm, Size(300, 720));vector<Rect> found, foundFiltered;//設計滑窗遍歷測試樣本:計算每個滑窗內的LBP特征,給SVM預測,把輸出為1的框畫出來。int m, n;Mat slideWinImg(30, 12, CV_8UC1, Scalar(0));Mat dstImg(30, 12, CV_8UC1, Scalar(0)); //LBP圖,可不輸出Mat lideWinImgFeatureMat;Mat sigleFeatureMat = Mat::zeros(1, descriptorDim, CV_32FC1); vector<int> descriptor;for(n=0; n<=testImgNorm.rows-30; n+=30) {for(m=0; m<=testImgNorm.cols-12; m+=4){slideWinImg = testImgNorm(Rect(m, n, 12, 30));if (slideWinImg.channels()>1) cvtColor(slideWinImg, slideWinImg, CV_BGR2GRAY);Mat extendLBPFeature;calExtendLBPFeature(slideWinImg, Size(3, 3), extendLBPFeature);//使用訓練的SVM模型預測測試樣本int predictResult = SVM.predict(extendLBPFeature);//cout<<"SVM訓練模型預測結果:"<<predictResult<<endl;if (predictResult==1){rectangle(copyImg,Point(m,n),Point(m+12,n+30),Scalar(0,255,0),1,1,0);}}}outputVideo <<copyImg; waitKey(100);}system("pause");return 0; }總結
以上是生活随笔為你收集整理的【机器学习】LBP+SVM实现特征检测的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一网打尽深度学习之卷积神经网络的经典网络
- 下一篇: 【OpenCV】8邻域种子填充法剔除短连