前几个月写了篇关于MATLAB实现SVM+HOG对图像进行多分类,链接:http://blog.csdn.net/cuixing001/article/details/70908064,先开始是用opencv实现的,可是识别效果很差,以为我写错代码了,后来纠结了好久好久,才发现是核函数选择有很大问题!这次改为线性核,效果在这些图片中(所用的图像数据集为:链接: https://pan.baidu.com/s/1i5OhC7z 密码: utn7)表现不错。
OpenCV代码如下:
//SVM多分类训练测试 #include <opencv2/opencv.hpp> #include <iostream> #include <fstream> using namespace cv; using namespace std; Size imageSize = Size(64, 64); void coumputeHog(const Mat& src, vector<float> &descriptors) { HOGDescriptor myHog = HOGDescriptor(imageSize, Size(16, 16), cvSize(8, 8), cvSize(8, 8), 9); myHog.compute(src.clone(),descriptors,Size(1,1),Size(0,0)); } int main(int argc, char** argv){ ifstream inLabels("myImageLabels.txt"), inImages("myImageList.txt"),inTestimage("myImagetest.txt"); string imageName; signed imageLabel; vector<Mat> vecImages; vector<int> vecLabels; CvSVM *mySVM = new CvSVM(); CvSVMParams params = CvSVMParams(); params.svm_type = CvSVM::C_SVC; params.kernel_type = CvSVM::LINEAR; params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 10000, 1e-10); vector<float> vecDescriptors; #if(1) //是否需要训练 while ((inImages>>imageName)&&(inLabels>>imageLabel)) { Mat src = imread(imageName, 0); resize(src, src, imageSize); vecImages.push_back(src); vecLabels.push_back(imageLabel); } inLabels.close(); inImages.close(); Mat dataDescriptors; Mat dataResponse = (Mat)vecLabels; for (size_t i = 0; i < vecImages.size(); i++) { Mat src = vecImages[i]; Mat tempRow; coumputeHog(src, vecDescriptors); if (i == 0) { dataDescriptors = Mat::zeros(vecImages.size(), vecDescriptors.size(), CV_32FC1); } tempRow = ((Mat)vecDescriptors).t(); tempRow.row(0).copyTo(dataDescriptors.row(i)); } mySVM->train(dataDescriptors, dataResponse, Mat(), Mat(), params); string svmName = to_string(88) + "_mysvm.xml"; mySVM->save(svmName.c_str()); #else mySVM->load("mysvm.xml"); #endif // 预测 string testPath; while (inTestimage >> testPath) { Mat test = imread(testPath, 0); resize(test, test, imageSize); vector<float> imageDescriptor; coumputeHog(test, imageDescriptor); Mat testDescriptor = Mat::zeros(1, imageDescriptor.size(), CV_32FC1); for (size_t i = 0; i < imageDescriptor.size(); i++) { testDescriptor.at<float>(0, i) = imageDescriptor[i]; } float label = mySVM->predict(testDescriptor, false); cout << label << endl; imshow("test image", test); waitKey(0); } inTestimage.close(); delete mySVM; return 0; }
上面代码用到"myImageLabels.txt", "myImageList.txt","myImagetest.txt"分别为训练图像标记,训练图像路径,测试图像路径。
里面保存内容格式如下:
label=1,2,3,4,5分别表示airplanes,butterfly,camera,scissors,sunflower这五类,测试效果如下,改成RBF效果就很差了:
每按下一次空格键就预测一张图片。