#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
#include <opencv2/ml/ml.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <string>
#include <io.h>
using namespace std;
using namespace cv;
using namespace cv::ml;
#define PosSamNO 480 //正样本个数
#define NegSamNO 3384 //负样本个数
#define HardExampleNO 0 //难例个数
int main(int argc, char** argv)
{
//HOG检测器,用来计算HOG描述子的
//检测窗口(48,48),块尺寸(16,16),块步长(8,8),cell尺寸(8,8),直方图bin个数9 param = CvSVMParams( CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.09, 1.0, 10.0, 0.5, 1.0, NULL, criteria );
cv::HOGDescriptor hog(cv::Size(64, 64), cv::Size(16, 16), cv::Size(16, 16), cv::Size(8, 8), 9);
int DescriptorDim;//HOG描述子的维数,由图片大小、检测窗口大小、块大小、细胞单元中直方图bin个数决定
SVM::Params params;
params.svmType = SVM::C_SVC;
params.C = 0.1;
params.kernelType = SVM::LINEAR;//SVM::LINEAR;//SVM::LINEAR;
params.termCrit = TermCriteria(TermCriteria::MAX_ITER, (int)10000, 1e-6);
//正样本图片路径文件,具体通过图片生成图片路径文件的代码,在我上传的资源里面可以找到
std::ifstream finPos("E:/opencv_studydocumence/opencv_study/HOG+SVM/code/Release/labels_20180206/svm20180206_x.txt");
//负样本图片的文件列表
std::ifstream finNeg("E:/opencv_studydocumence/opencv_study/HOG+SVM/code/Release/labels_20180206/svmtrain_neg.txt");
std::string ImgName;
//所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数
cv::Mat sampleFeatureMat;
//训练样本的类别向量,行数等于所有样本的个数,列数等于1;1表示有目标,-1表示无目标
cv::Mat sampleLabelMat;
//依次读取正样本图片,生成HOG描述子
for (int num = 0; num < PosSamNO && getline(finPos, ImgName); num++)
{
std::cout << "Processing:" << ImgName << std::endl;
std::cout << "1" << std::endl;
cv::Mat image = cv::imread(ImgName);
//HOG描述子向量
std::vector<float> descriptors;
//计算HOG描述子,检测窗口移动步长(8,8)
hog.compute(image, descriptors, cv::Size(8, 8));
//处理第一个样本时初始化特征向量矩阵和类别矩阵,因为只有知道了特征向量的维数才能初始化特征向量矩阵
if (0 == num)
{
//HOG描述子的维数
DescriptorDim = descriptors.size();
//初始化所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数sampleFeatureMat
sampleFeatureMat = cv::Mat::zeros(PosSamNO + NegSamNO + HardExampleNO, DescriptorDim, CV_32FC1);
//初始化训练样本的类别向量,行数等于所有样本的个数,列数等于1
sampleLabelMat = cv::Mat::zeros(PosSamNO + NegSamNO + HardExampleNO, 1, CV_32SC1);
}
//将计算好的HOG描述子复制到样本特征矩阵sampleFeatureMat
for (int i = 0; i < DescriptorDim; i++)
{
//第num个样本的特征向量中的第i个元素
sampleFeatureMat.at<float>(num, i) = descriptors[i];
}
//正样本类别为17,有目标
sampleLabelMat.at<float>(num, 0) = 9;
}
//依次读取负样本图片,生成HOG描述子
for (int num = 0; num < NegSamNO && getline(finNeg, ImgName); num++)
{
std::cout << "-1"<< std::endl;
std::cout << "Processing:" << ImgName << std::endl;
cv::Mat src = cv::imread(ImgName);
cv::resize(src, src, cv::Size(64, 64));
//HOG描述子向量
std::vector<float> descriptors;
//计算HOG描述子,检测窗口移动步长(8,8)
hog.compute(src, descriptors, cv::Size(8, 8));
std::cout << "descriptor dimention:" << descriptors.size() << std::endl;
//将计算好的HOG描述子复制到样本特征矩阵sampleFeatureMat
for (int i = 0; i < DescriptorDim; i++)
{
//第PosSamNO+num个样本的特征向量中的第i个元素
sampleFeatureMat.at<float>(num + PosSamNO, i) = descriptors[i];
}
//负样本类别为-1,无目标
sampleLabelMat.at<float>(num + PosSamNO, 0) = -1;
}
//处理HardExample负样本
if (HardExampleNO > 0)
{
//HardExample负样本的文件列表
std::ifstream finHardExample("svmtrain_hard.txt");
//依次读取HardExample负样本图片,生成HOG描述子
for (int num = 0; num < HardExampleNO && getline(finHardExample, ImgName); num++)
{
std::cout << "2" << std::endl;
std::cout << "Processing:" << ImgName << std::endl;
cv::Mat src = cv::imread(ImgName, cv::IMREAD_GRAYSCALE);
cv::resize(src, src, cv::Size(64, 64));
//HOG描述子向量
std::vector<float> descriptors;
//计算HOG描述子,检测窗口移动步长(8,8)
hog.compute(src, descriptors, cv::Size(8, 8));
//将计算好的HOG描述子复制到样本特征矩阵sampleFeatureMat
for (int i = 0; i < DescriptorDim; i++)
{
//第PosSamNO+num个样本的特征向量中的第i个元素
sampleFeatureMat.at<float>(num + PosSamNO + NegSamNO, i) = descriptors[i];
}
//负样本类别为-1,无目标
sampleLabelMat.at<float>(num + PosSamNO + NegSamNO, 0) =2;
}
}
//训练SVM分类器
//迭代终止条件,当迭代满1000次或误差小于FLT_EPSILON时停止迭代
std::cout << "start training SVM" << std::endl;
//cout << "Starting training process" << endl;
Ptr<SVM> svm = StatModel::train<SVM>(sampleFeatureMat, ROW_SAMPLE, sampleLabelMat, params);
cout << "Finished training process" << endl;
//训练分类器
//svm->train(td);
std::cout << "训练完成" << std::endl;
//将训练好的SVM模型保存为xml文件
svm->save("20180206_xmls/svmx_20180206.xml");
return 0;
}