首先我们需要正负样本两种数据 svm虽然支持少量数据的分类,但原则上数据更多效果更佳
这里面我们采用正样本232张 负样本555张。推荐负样本是正样本的2-3倍。这里我们做的是对老鼠特征的识别,正样本都是包含老鼠的 ,负样本不能包含老鼠。然后所有训练样本的大小尺寸要缩成一致。把winsize,blocksize,blockstride,cell,winstride越小计算的当然越仔细。只是这样会大量冗余的计算,造成计算时间过长,影响实际效率。
在参数方面的选择 可分为线性可分,线性不可分,非线性可分 其中对应不同的核函数
主要是利用交叉正则和穷举求出参数c和g来达到效果的最优,其中本文用的是线性可分方法。svm参数的设置诸君可以自己尝试修改,毕竟不同的样本有不同的方案。
#include <iostream>
#include <fstream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/ml/ml.hpp>
using namespace std;
using namespace cv;
using namespace cv::ml;
#define plus 232
#define minus 555
void hogsvm(HOGDescriptor &hog)
{
ifstream pluspath("data\\plus-data\\plus-data.txt");//正样本路径
ifstream minuspath("data\\minus-data\\minus-data.txt");//负样本路径
string name;//txt中每一行图片的名字 注意一定要是绝对路径
int descriptordim;//特征向量的维数
Mat samplefeaturemat;//所以训练样本的特征向量矩阵 行数为样本数,列数为hog特征向量
Mat samplelabel;//样本标签 1,-1
cout << "开始计算" << endl;
for (int num = 0; num < plus&&getline(pluspath, name); num++)//遍历正样本txt
{
Mat temple = imread(name);//用来代表正样本种的每一个图片
vector<float> descriptor;//样本的特征向量
hog.compute(temple, descriptor, Size(1, 1));//计算特征向量
descriptordim = descriptor.size();//向量的维数
if (num == 0)
{
samplefeaturemat = Mat::zeros(plus+minus, descriptordim, CV_32FC1);//初始化所有正样本特征向量组成的矩阵
samplelabel = Mat::zeros(plus+minus, 1, CV_32SC1);//初始化所有正样本的标签为1
}
for (int i = 0; i < descriptordim; i++)
{
samplefeaturemat.at<float>(num, i) = descriptor[i];//每个正特征向量都存进去
}
samplelabel.at<int>(num, 0) = 1;//正样本矩阵都为1
}
cout << "正样本计算完毕" << endl;
for (int num = 0; num < minus&&getline(minuspath, name); num++)//遍历负样本txt
{
Mat temple = imread(name);//用来代表负样本种的每一个图片
vector<float> descriptor;//样本的特征向量
hog.compute(temple, descriptor, Size(1,1));//计算特征向量
descriptordim = descriptor.size();//向量的维数
for (int i = 0; i < descriptordim; i++)
{
samplefeaturemat.at<float>(num + plus, i) = descriptor[i];//每个负特征向量相加得到总的负特征向量
}
samplelabel.at<int>(num + plus, 0) = -1;//负样本矩阵为-1
}
cout << "负样本计算完毕" << endl;
cout << endl << "开始训练分类" << endl;
Ptr<SVM> svm = SVM::create();//创建一个svm
svm->setType(SVM::C_SVC);//svm分类器的类型 有5种选择
svm->setKernel(SVM::RBF); //svm的核函数选择 有4种选择
svm->setGamma(0.5);//gamma是rbf核函数的参数,决定支持向量的个数,越小,支持向量越多,反之越少
svm->train(samplefeaturemat, ROW_SAMPLE, samplelabel);
svm->save("mouse.xml");
cout << "训练成功" << endl;
}
int main()
{
HOGDescriptor hog(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
hogsvm(hog);
return 0;
}
我们可以看到其实就是特征向组成的矩阵