先暂时把opencv3的具有参考价值的文章放一下:
1、主要参考这个文章,但是他的是opencv2 文章名称: 使用 svm+hog 训练,检测手写数字:https://blog.csdn.net/weixin_37721518/article/details/74187127
2、这个是opencv3的,部分参考这个,也理解了一些参数如何修改https://blog.csdn.net/almost_miao/article/details/79115939
3、opencv3的https://blog.csdn.net/u014774106/article/details/60763660
4、https://blog.csdn.net/wang382758656/article/details/52723674
5、https://blog.csdn.net/rrrfff/article/details/76796341
6、http://www.cnblogs.com/tornadomeet/archive/2012/08/15/2640754.html
7、https://blog.csdn.net/u010869312/article/details/44927721
8】https://blog.csdn.net/iamzhangzhuping/article/details/51254567
我修改成功的训练代码
/**********************************************************************
2018.5.23:SVM训练 //在 配置SVM训练器参数CvSVMParams SVM_params;这里有问题
2018.5.25:1、因为例程是opencv2的,opencv3里的svm的一些声明格式有了些许变化,修改了
2、批量读取图片出现错误,原来是一个参数变量出现错误,说明警告也可能造成致命错误
2018.05.31: 之前的svm训练只是二分类,而且特征提取是简单的像素值特征,现在训0-9的数字,且hog特征
***************************************************************/
#include "opencv2/opencv.hpp"
#include //hog特征的c文件
#include
#include
#include
#include
#include
#include
#include //查找文件相关函数
#include
#include //测试程序运行时间
#include "windows.h"
#include "fstream"
using namespace std;
using namespace cv;
using namespace cv::ml;
int main()
{
检测窗口(128,128),块尺寸(16,16),块步长(8,8),cell尺寸(8,8),直方图bin个数9
//HOGDescriptor hog(Size(128, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
HOG检测器,用来计算HOG描述子的
//int DescriptorDim;//HOG描述子的维数,由图片大小、检测窗口大小、块大小、细胞单元中直方图bin个数决定
//Mat sampleFeatureMat;//所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数
//Mat sampleLabelMat;//训练样本的类别向量,行数等于所有样本的个数,列数等于1;1表示有人,-1表示无人
Mat classes;
vector<string> img_path;//输入文件名变量
vector<int> img_catg;
int nLine = 0;
string buf;
ifstream svm_data("E:/OCR_Recognition/opencv_project/SVM_train_data/hb.txt");//训练样本图片的路径都写在这个txt文件中,使用bat批处理文件可以得到这个txt文件
unsigned long n;
while (svm_data)//将训练样本文件依次读取进来
{
if (getline(svm_data, buf))
{
nLine++;
if (nLine % 2 == 0)//注:奇数行是图片全路径,偶数行是标签
{
img_catg.push_back(atoi(buf.c_str()));//atoi将字符串转换成整型,标志(0,1,2,...,9),注意这里至少要有两个类别,否则会出错
}
else
{
img_path.push_back(buf);//图像路径
}
}
}
svm_data.close();//关闭文件
Mat data_mat, labels_mat;
int nImgNum = nLine / 2; //nImgNum是样本数量,只有文本行数的一半,另一半是标签
cout << " 共有样本个数为: " << nImgNum << endl;
//data_mat为所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数
data_mat =Mat::zeros(nImgNum, 324, CV_32FC1); //行、列、类型;第二个参数,即矩阵的列是由下面的descriptors的大小决定的,可以由descriptors.size()得到,且对于不同大小的输入训练图片,这个值是不同的
//类型矩阵,存储每个样本的类型标志
//labels_mat为训练样本的类别向量,行数等于所有样本的个数,列数等于1;暂时,后面会修改,比如样本0,就为0,样本1就为1
labels_mat = Mat::zeros(nImgNum, 1, CV_32SC1);
Mat src;
Mat trainImg = Mat(Size(28, 28), CV_8UC3);//需要分析的图片,这里默认设定图片是28*28大小,所以上面定义了324,如果要更改图片大小,可以先用debug查看一下descriptors是多少,然后设定好再运行
//处理HOG特征
for (string::size_type i = 0; i != img_path.size(); i++)
{
cout << " \n第 " << i << " 次循环\n" << endl;
src = imread(img_path[i].c_str(),1);
if (src.empty())
{
cout << " can not load the image: " << img_path[i].c_str() << endl;
continue;
}
cout << " 处理: " << img_path[i].c_str() << endl;
resize(src, trainImg, trainImg.size());
//检测窗口(64,128),块尺寸(16,16),块步长(8,8),cell尺寸(8,8),直方图bin个数9 ,需要修改
HOGDescriptor *hog = new HOGDescriptor(Size(28, 28), Size(14, 14), Size(7, 7), Size(7, 7), 9);
vector<float>descriptors;//存放结果 为HOG描述子向量
hog->compute(trainImg, descriptors, Size(1, 1), Size(0, 0)); //Hog特征计算,检测窗口移动步长(1,1)
cout << "HOG描述子向量个数 : " << descriptors.size() << endl;
n = 0;
int number = descriptors.size();
//将计算好的HOG描述子复制到样本特征矩阵data_mat
for (int i = 0; i < number; i++)
{
data_mat.at<float>(i, n) = descriptors[i];//第1个样本的特征向量中的第n个元素
n++;
}
labels_mat.at<int>(i, 0) = img_catg[i];
cout << " 处理完毕: " << img_path[i].c_str() << " " << img_catg[i] << endl;
}
Mat(labels_mat).copyTo(classes);
// 创建分类器并设置参数
Ptr SVM_params = SVM::create();
SVM_params->setType(SVM::C_SVC);
SVM_params->setKernel(SVM::RBF); //核函数,后期重点分析的地方 SVM::RBF为径向基(RBF)核函数(高斯核函数)
SVM_params->setDegree(10.0);
SVM_params->setGamma(0.09);
SVM_params->setCoef0(1.0);
SVM_params->setC(10.0);
SVM_params->setNu(0.5);
SVM_params->setP(1.0);
SVM_params->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 0.01));
Mat labelMat1(labels_mat.rows, labels_mat.cols, CV_32SC1);
for (int i = 0; i < labels_mat.rows; i++)
{
for (int j = 0; j < labels_mat.cols; j++)
{
labelMat1.at<int>(i, j) = labels_mat.at<float>(i, j);
}
}
cout << "开始训练..." << endl;
Ptr traindata = ml::TrainData::create(data_mat, ROW_SAMPLE, classes);
// 训练分类器
SVM_params->train(traindata);
//保存模型
SVM_params->save("svm.xml");
cout << "训练好了!!!" << endl;
这段代码,我要说以下几个关键点
1、resize(src, trainImg, trainImg.size());需要把读取进来的图片调整尺寸大小,不然hog描述子向量需要重新修改一下,等于descriptors.size()
2、原来的函数 cvmSet(data_mat,i,n,*iter);在opencv3里没有,但是可以改成
int number = descriptors.size();
//将计算好的HOG描述子复制到样本特征矩阵data_mat
for (int i = 0; i < number; i++)
{
data_mat.at<float>(i, n) = descriptors[i];//第i个样本的特征向量中的第n个元素
n++;
}
关键要知道n和i所代表意思,n代表hog描述子的元素,i代表第几个样本