前几个月写了篇关于MATLAB实现SVM+HOG对图像进行多分类,链接:http://blog.youkuaiyun.com/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效果就很差了:
每按下一次空格键就预测一张图片。