opencv3/4 svm+hog训练自己的数据集——附源码
c语言版本opencv3/4 svm+hog训练自己的数据集——仪表盘的检测1
项目背景:最近在做一个机器人巡检仪表盘的项目,需要识别众多的仪表盘并读数。因此需要用svm识别出表盘大体位置再进行摆盘示数的识别。
- 话不多说,先上效果图
训练的图片比较少,因此检测框有些许的歪斜。可以增加图片达到更准确的检测效果。
一、训练准备
训练集及测试集:
链接:https://pan.baidu.com/s/19m0-WSNqWYYc0U94tAUyog
提取码:rcoc
复制这段内容后打开百度网盘手机App,操作更方便哦
路径位置:
正样本是128128的仪表图片,如下图:
负样本是从整张图片集合中裁剪的128128的图片:
下面是将最终要识别的19201080等分辨率图片裁剪成128128小图片的代码:
/****************************************************************************************************************************
* 文件名:cankao4.cpp
* 文件功能:训练并测试SVM的前一步,将图片分辨率进行调整,包括训练集和测试集的调整
* 参考来源:csdn https://xiaorun.blog.csdn.net/article/details/82902267?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param
* 编写时间:2020.10.17
* 作者:狄云
* 版本:1.0.0
* 时间:2020.10.17
* 内容:将图片分辨率进行调整
* 版本:1.1.0
* 时间:2020.10.21
* 内容:增加将正样本归一化到128*128
python代码:
功能:将当期文件夹下的文件名写到txt文件里
def read_directory(directory_name):
for filename in os.listdir(directory_name):
print(filename) # 仅仅是为了测试
fw.write(filename + '\n') # 打印成功信息
# img = cv2.imread(directory_name + "/" + filename)
# #####显示图片#######
# cv2.imshow(filename, img)
# cv2.waitKey(0)
# #####################
#
# #####保存图片#########
# cv2.imwrite("D://wangyang//face1" + "/" + filename, img)
images_path0='./'
txt_save_path0='./train.txt'
fw = open(txt_save_path0, "w")
read_directory(images_path0)#这里传入所要读取文件夹的绝对路径,加引号(引号不能省略!)
****************************************************************************************************************************/
#include <iostream>
#include <fstream>
#include <stdlib.h> //srand()和rand()函数
#include <time.h> //time()函数
#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;
int CropImageCount = 0; //裁剪出来的负样本图片个数
string num2str(int i)
{
stringstream ss;
ss << i;
return ss.str();
}
//模式选择
#define MODE_1 0 //将训练集调整为128*128的
#define MODE_2 1 //将一张图片裁剪成各种128*128大小的作为负样本
int main()
{
#if MODE_1
Mat src,dst;
string ImgName;
string saveName;//裁剪出来的负样本图片文件名
ifstream fin("E:\\VS_project\\opencv_1017_test\\opencvtest\\train_picture\\train\\pos\\2\\train.txt");//打开原始正样本图片文件列表
//一行一行读取文件列表
while (getline(fin, ImgName))
{
cout << "处理:" << ImgName << endl;
ImgName = "E:\\VS_project\\opencv_1017_test\\opencvtest\\train_picture\\train\\pos\\2\\" + ImgName;
cout << ImgName;
src = imread(ImgName, 1);//读取图片
resize(src, dst, Size(128,128));
CropImageCount++;
saveName = "E:\\VS_project\\opencv_1017_test\\opencvtest\\train_picture\\train\\pos\\2\\train_pos_img\\" + num2str(CropImageCount) + ".jpg";
//sprintf(saveName,"F:\\BaiduNetdiskDownload\\INRIADATA\\normalized_images\\train\\train_neg_img\\noperson%06d.jpg",++CropImageCount);//生成裁剪出的负样本图片的文件名
imwrite(saveName, dst);//保存文件
}
#endif
#if MODE_2
Mat src;
string ImgName;
string saveName;//裁剪出来的负样本图片文件名
ifstream fin("E:\\VS_project\\opencv_1017_test\\opencvtest\\train\\neg\\train.txt");//打开原始负样本图片文件列表
//一行一行读取文件列表
while (getline(fin, ImgName))
{
cout << "处理:" << ImgName << endl;
ImgName = "E:\\VS_project\\opencv_1017_test\\opencvtest\\train\\neg\\" + ImgName;
cout << ImgName;
src = imread(ImgName, 1);//读取图片
//printf("ImhName%s", ImgName);
//cout<<"宽:"<<src.cols<<",高:"<<src.rows<<endl;
//图片大小应该能能至少包含一个64*128的窗口
if (src.cols >= 128 && src.rows >= 128)
{
srand(time(NULL));//设置随机数种子 time(NULL)表示当前系统时间
//从每张图片中随机采样10个64*128大小的不包含人的负样本
for (int i = 0; i<10; i++)
{
int x = (rand() % (src.cols - 128)); //左上角x坐标
int y = (rand() % (src.rows - 128)); //左上角y坐标
//cout<<x<<","<<y<<endl;
Mat imgROI = src(Rect(x, y, 128, 128));
CropImageCount++;
saveName = "E:\\VS_project\\opencv_1017_test\\opencvtest\\train\\neg\\new\\" + num2str(CropImageCount) + ".jpg";
//sprintf(saveName,"F:\\BaiduNetdiskDownload\\INRIADATA\\normalized_images\\train\\train_neg_img\\noperson%06d.jpg",++CropImageCount);//生成裁剪出的负样本图片的文件名
imwrite(saveName, imgROI);//保存文件
}
}
}
#endif
return 0;
}
二、训练及测试代码:
包含训练和测试代码,通过开头那个模式选择。
/****************************************************************************************************************************
* 文件名:cankao4.cpp
* 文件功能:svm训练单分类,且有检测框那种
* 参考来源:csdn https://xiaorun.blog.csdn.net/article/details/82902267?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param
* 编写时间:2020.10.17
* 作者:狄云
* 版本:1.0.0
* 时间:2020.10.17
* 内容:初步运行,跑通训练及测试。
多分类及单分类区别介绍
参数介绍
https://www.cnblogs.com/br170525/p/9236479.html
多尺度分类介绍
https://blog.csdn.net/tanmx219/article/details/82012519
https://blog.csdn.net/sazass/article/details/94431965
****************************************************************************************************************************/
#include <iostream>
#include <fstream>
#include <stdlib.h> //srand()和rand()函数
#include <time.h> //time()函数
#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>
#include<opencv2\opencv.hpp>
#include <opencv2\imgproc\types_c.h>
//模式选择
#define TRAIN_MODE 0 //训练模式
#define TEST_ONE_PICTURE_MODE_1 1 //测试一张图片模式1
#define TEST_ONE_PICTURE_MODE_2 0 //测试一张图片模式2
using namespace std;
using namespace cv;
using namespace ml;
void get_svm_detector(const Ptr< SVM > & svm, vector< float > & hog_detector);
void convert_to_ml(const std::vector< Mat > & train_samples, Mat& trainData);
void load_images(const String & dirname, vector< Mat > & img_lst, bool showImages);
void sample_neg(const vector< Mat > & full_neg_lst, vector< Mat > & neg_lst, const Size & size);
void computeHOGs(const Size wsize, const vector< Mat > & img_lst, vector< Mat > & gradient_lst);
//函数定义
///
///
///
void get_svm_detector(const Ptr< SVM >& svm, vector< float > & hog_detector)
{ // get the support vectors
Mat sv = svm->getSupportVectors();
const int sv_total = sv.rows; // get the decision function
Mat alpha, svidx;
double rho = svm->getDecisionFunction(0, alpha, svidx);
//CV_Assert(alpha.total() == 1 && svidx.total() == 1 && sv_total == 1); //括号中的条件不满足时,返回错误
//CV_Assert((alpha.type() == CV_64F && alpha.at<double>(0) == 1.)||(alpha.type() == CV_32F && alpha.at<float>(0) == 1.f));
//CV_Assert(sv.type() == CV_32F); hog_detector.clear();
hog_detector.resize(sv.cols + 1);
memcpy(&hog_detector[0], sv.ptr(), sv.cols * sizeof(hog_detector[0])); //memcpy指的是c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。
hog_detector[sv.cols] = (float)-rho;
}
///
///
///
/** Convert training/testing set to be used by OpenCV Machine Learning algorithms.*
TrainData is a matrix of size (#samples x max(#cols,#rows) per samples), in 32FC1.*
Transposition of samples are made if needed.*/
///
///
///
void convert_to_ml(const vector< Mat > & train_samples, Mat& trainData)
{
//--Convert data
const int rows = (int)train_samples.size(); //行数等于训练样本个数
const int cols = (int)std::max(train_samples[0].cols, train_samples[0].rows); //列数取样本图片中宽度与高度中较大的那一个
Mat tmp(1, cols, CV_32FC1); //< used for transposition if needed
trainData = Mat(rows, cols, CV_32FC1);
for (size_t i = 0; i < train_samples.size(); ++i)
{
CV_Assert(train_samples[i].cols == 1 || train_samples[i].rows == 1);
if (train_samples[i].cols == 1)
{
transpose(train_samples[i], tmp);
tmp.copyTo(trainData.row((int)i));
}
else if (train_samples[i].rows == 1)
{
train_samples[i].copyTo(trainData.row((int)i));
}
}
}
///
///
///
void load_images(const String & dirname, vector< Mat > & img_lst, bool showImages = false)
{
//载入目录下的图片样本
vector< String > files;
glob(dirname, files);
//返回一个包含有匹配文件/目录的数组。出错则返回false
for (size_t i = 0; i < files.size(); ++i)
{
Mat img = imread(files[i]); // load the image
if (img.empty()) // invalid image, skip it.
{
cout << files[i] << " is invalid!" << endl;
continue;
}
if (showImages)
{
imshow("image", img);
waitKey(1);
}
img_lst.push_back(img); //将Img压入img_lst
}
}
///
///
///
void sample_neg(const vector< Mat > & full_neg_lst, vector< Mat > & neg_lst, const Size & size)
{
//该函数对每一个负样本采样出一个随机的64*128尺寸的样本,由于之前已经采样过了,所以main函数中没有使用该函数
Rect box; box.width = size.width; //等于检测器宽度
box.height = size.height; //等于检测器高度
const int size_x = box.width;
const int size_y = box.height;
srand((unsigned int)time(NULL)); //生成随机数种子
for (size_t i = 0; i < full_neg_lst.size(); i++)
{
//对每个负样本进行裁剪,随机指定x,y,裁剪一个尺寸为检测器大小的负样本
box.x = rand() % (full_neg_lst[i].cols - size_x);
box.y = rand() % (full_neg_lst[i].rows - size_y);
Mat roi = full_neg_lst[i](box);
neg_lst.push_back(roi.clone());
}
}
///
///
///
void computeHOGs(const Size wsize, const vector< Mat > & img_lst, vector< Mat > & gradient_lst)
{
//计算HOG特征
HOGDescriptor hog;
hog.winSize = wsize;
//Rect r = Rect(0, 0, wsize.width, wsize.height);
//r.x += (img_lst[0].cols - r.width) / 2; //正样本图片的尺寸减去检测器的尺寸,再除以2
//r.y += (img_lst[0].rows - r.height) / 2;
Mat gray; vector< float > descriptors;
for (size_t i = 0; i< img_lst.size(); i++)
{
cvtColor(img_lst[i], gray, COLOR_BGR2GRAY);
hog.compute(gray, descriptors, Size(8, 8), Size(0, 0)); //Size(8,8)为窗口移动步长,
gradient_lst.push_back(Mat(descriptors).clone());
}
}
///
///
///
int test_trained_detector(String obj_det_filename, String test_dir, String videofilename)
{
//当videofilename为空,则只检测图片中的行人
cout << "Testing trained detector..." << endl;
HOGDescriptor hog;
hog.load(obj_det_filename);
vector< String > files;
glob(test_dir, files);
int delay = 0;
VideoCapture cap;
if (videofilename != "")
{
cap.open(videofilename);
}
obj_det_filename = "testing " + obj_det_filename;
namedWindow(obj_det_filename, WINDOW_NORMAL);
for (size_t i = 0;; i++)
{
Mat img;
if (cap.isOpened())
{
cap >> img;
delay = 1;
}
else if (i < files.size())
{
img = imread(files[i]);
}
if (img.empty())
{
return 0;
}
vector< Rect > detections;
vector< double > foundWeights;
hog.detectMultiScale(img, detections, foundWeights);
for (size_t j = 0; j < detections.size(); j++)
{
if (foundWeights[j] < 0.5)
continue; //清楚权值较小的检测窗口
Scalar color = Scalar(0, foundWeights[j] * foundWeights[j] * 200, 0);
rectangle(img, detections[j], color, img.cols / 400 + 1);
}
imshow(obj_det_filename, img);
if (27 == waitKey(delay))
{
return 0;
}
}
return 0;
}
int main(int argc, char** argv)
{
#if TEST_ONE_PICTURE_MODE_1 //测试单张图片模式
//当videofilename为空,则只检测图片中的行人
cout << "Testing trained detector..." << endl;
HOGDescriptor hog;
//hog.load("D:/my_detector.yml");
Mat dst;
hog.load("E:/VS_project/opencv_1017_test/opencvtest/train/1024_yibaio_1_duomubiao.yml");
Mat test_img = imread("test/0_0023.jpg");//读取图片
resize(test_img, test_img, Size(400,400));
//namedWindow("测试图片", 0);
//imshow("测试图片", test_img);
//waitKey(1000);
if (test_img.empty())
{
cout << " 待预测图像不存在: " << endl;
}
vector< Rect > detections;
vector< double > foundWeights;
hog.detectMultiScale(test_img, detections, foundWeights);
for (size_t j = 0; j < detections.size(); j++)
{
if (foundWeights[j] < 0.)
continue; //清楚权值较小的检测窗口
Scalar color = Scalar(0, 255, 0);
rectangle(test_img, detections[j], color, test_img.cols / 400 + 1);
}
namedWindow("result", 0);
imshow("result", test_img);
waitKey(1000);
waitKey(1000);
#endif
#if TEST_ONE_PICTURE_MODE_2 //测试单张图片模式
//当videofilename为空,则只检测图片中的行人
cout << "Testing trained detector..." << endl;
Ptr<ml::SVM>svm = ml::SVM::load("svm6_13.xml");//加载训练好的xml文件,
Mat test_img = imread("333333.jpg");//读取图片
if (test_img.empty())
{
cout << " 待预测图像不存在: " << endl;
}
namedWindow("测试图片", 0);
imshow("测试图片", test_img);
waitKey(1000);
cvtColor(test_img, test_img, COLOR_BGR2GRAY);
int thickness = -1;
int lineType = 8;
thickness = 2;
lineType = 8;
HOGDescriptor hog;
hog.winSize = Size(128, 128);// Set the trained svm to my_hog //hog描述子
//HOGDescriptor *hog = new HOGDescriptor(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
/*************************************************************************************************
线性SVM训练完成后得到的XML文件里面,有一个数组,叫做support vector,还有一个数组,叫做alpha,有一个浮点数,叫做rho;
将alpha矩阵同support vector相乘,注意,alpha*supportVector,将得到一个列向量。之后,再该列向量的最后添加一个元素rho。
如此,变得到了一个分类器,利用该分类器,直接替换opencv中行人检测默认的那个分类器(cv::HOGDescriptor::setSVMDetector()),
就可以利用你的训练样本训练出来的分类器进行行人检测了。
***************************************************************************************************/
vector< float > hog_detector;
get_svm_detector(svm, hog_detector);
hog.setSVMDetector(hog_detector);
vector< Rect > detections;
vector< double > foundWeights;
hog.detectMultiScale(test_img, detections, foundWeights);
for (size_t j = 0; j < detections.size(); j++)
{
if (foundWeights[j] < 0.5)
continue; //清楚权值较小的检测窗口
//Scalar color = Scalar(0, foundWeights[j] * foundWeights[j] * 200, 0);
Scalar color = Scalar(0, 255, 0);
rectangle(test_img, detections[j], color, test_img.cols / 400 + 1);
}
namedWindow("result", 0);
imshow("result", test_img);
waitKey(1000);
waitKey(1000);
#endif
#if TRAIN_MODE
cout << "HELLO WORLD" << endl;
const char* keys =
{
"{help h| | show help message}"
"{pd1 | E:/VS_project/opencv_1017_test/opencvtest/train/1/ | path of directory contains possitive images}" //正样本1
"{pd2 | E:/VS_project/opencv_1017_test/opencvtest/train/2/ | path of directory contains possitive images}" //正样本2
"{nd | E:/VS_project/opencv_1017_test/opencvtest/train/neg/ | path of directory contains negative images}" //负样本
"{td | E:/VS_project/opencv_1017_test/opencvtest/test/ | path of directory contains test images}" //测试样本
"{fn | E:/VS_project/opencv_1017_test/opencvtest/train/1024_yibaio_1_duomubiao.yml | file name of trained SVM}" //保存的模型
"{tv | | test video file name}"
"{dw | 128 | width of the detector}" //检测器宽度
"{dh | 128 | height of the detector}"
"{d |false| train twice}"
"{t |true| test a trained detector}"
"{v |false| visualize training steps}"
};
CommandLineParser parser(argc, argv, keys); //命令行函数,读取keys中的字符, 其中key的格式为:名字 简称| 内容 |提示字符。
if (parser.has("help"))
{
parser.printMessage();
exit(0);
}
String pos_dir_1 = parser.get< String >("pd1"); //正样本1目录
String pos_dir_2 = parser.get< String >("pd2"); //正样本2目录
cout << pos_dir_1 << endl;
cout << pos_dir_2 << endl;
String neg_dir = parser.get< String >("nd"); //负样本目录
String test_dir = parser.get< String >("td"); //测试样本目录
String obj_det_filename = parser.get< String >("fn"); //训练好的SVM检测器文件名
String videofilename = parser.get< String >("tv"); //测试视频
int detector_width = parser.get< int >("dw"); //检测器宽度
int detector_height = parser.get< int >("dh"); //检测器高度
bool test_detector = parser.get< bool >("t"); //测试训练好的检测器
bool train_twice = parser.get< bool >("d"); //训练两次
bool visualization = parser.get< bool >("v"); //训练过程可视化(建议false,不然爆炸)
//根据评论,以下5行代码在初次运行时,请注释掉。该段代码是为了对已经训练好的模型进行测试的,初次运行时,因为还未有任何模型参数,所以可能会报错。
//if (test_detector) //若为true,测对测试集进行测试
//{
// test_trained_detector(obj_det_filename, test_dir, videofilename);
// exit(0);
//}
if (pos_dir_1.empty() || pos_dir_2.empty() || neg_dir.empty()) //检测训练集和测试集合是否是空的
{
parser.printMessage();
cout << "Wrong number of parameters.\n\n"
<< "Example command line:\n"
<< argv[0]
<< " -pd=/INRIAPerson/96X160H96/Train/pos -nd=/INRIAPerson/neg -td=/INRIAPerson/Test/pos -fn=HOGpedestrian96x160.yml -d\n"
<< "\nExample command line for testing trained detector:\n"
<< argv[0]
<< " -t -dw=96 -dh=160 -fn=HOGpedestrian96x160.yml -td=/INRIAPerson/Test/pos";
exit(1);
}
vector< Mat > pos_lst_1, //正样本1图片向量
pos_lst_2, //正样本2图片向量
full_neg_lst, //负样本图片向量
neg_lst, //采样后的负样本图片向量
gradient_lst; //HOG描述符存入到该梯度信息里面
vector< int > labels; //标签向量
clog << "Positive images are being loaded..."; //正样本读取结束
/***************************************************************************************************************
1、加载正样本1图片
****************************************************************************************************************/
load_images(pos_dir_1, pos_lst_1, visualization); //加载图片 pos正样本的尺寸为96*160
if (pos_lst_1.size() > 0)
{
clog << "...[done]" << endl;
}
else
{
clog << "no image in " << pos_dir_1 << endl;
return 1;
}
Size pos_image_size = pos_lst_1[0].size();
//令尺寸变量pos_image_size=正样本尺寸
//检测所有正样本是否具有相同尺寸
for (size_t i = 0; i < pos_lst_1.size(); ++i)
{
if (pos_lst_1[i].size() != pos_image_size)
{
cout << "All positive images should be same size!" << endl;
exit(1);
}
}
pos_image_size = pos_image_size / 8 * 8;
//令pos_image_size的尺寸为检测器的尺寸
if (detector_width && detector_height)
{
pos_image_size = Size(detector_width, detector_height);
} labels.assign(pos_lst_1.size(), +1);
//assign()为labels分配pos_lst.size()大小的容器,用+1填充 表示为正样本
const unsigned int old = (unsigned int)labels.size(); //旧标签大小
clog << "Negative 1 images are being loaded...";
/**************************************************************************************************************
2、加载正样本2图片
****************************************************************************************************************/
//load_images(pos_dir_2, pos_lst_2, visualization); //加载图片 pos正样本的尺寸为96*160
//if (pos_lst_2.size() > 0)
//{
// clog << "...[done]" << endl;
//}
//else
//{
// clog << "no image in " << pos_dir_2 << endl;
// return 1;
//}
Size pos_image_size = pos_lst_2[0].size();
令尺寸变量pos_image_size=正样本尺寸
检测所有正样本是否具有相同尺寸
//for (size_t i = 0; i < pos_lst_2.size(); ++i)
//{
// if (pos_lst_2[i].size() != pos_image_size)
// {
// cout << "All positive images should be same size!" << endl;
// exit(1);
// }
//}
//pos_image_size = pos_image_size / 8 * 8;
令pos_image_size的尺寸为检测器的尺寸
//if (detector_width && detector_height)
//{
// pos_image_size = Size(detector_width, detector_height);
//}
labels.assign(pos_lst_2.size(), +2);
//labels.insert(labels.end(), pos_lst_2.size(), +2);
assign()为labels分配pos_lst.size()大小的容器,用+1填充 表示为正样本
//old = (unsigned int)labels.size(); //旧标签大小
//clog << "Negative 2 images are being loaded...";
/**************************************************************************************************************
3、加载负样本图片
****************************************************************************************************************/
load_images(neg_dir, neg_lst, false); //加载负样本图片
//sample_neg(full_neg_lst, neg_lst, pos_image_size);
clog << "...[done]" << endl;
labels.insert(labels.end(), neg_lst.size(), -1);
//在labels向量的尾部添加neg_lst.size()大小的容器,用-1填充 表示为负样本
CV_Assert(old < labels.size()); //CV_Assert()作用:CV_Assert()若括号中的表达式值为false,则返回一个错误信息。
/**************************************************************************************************************
4、计算正样本1 HOG特征
****************************************************************************************************************/
clog << "Histogram of Gradients are being calculated for positive images...";
computeHOGs(pos_image_size, pos_lst_1, gradient_lst); //计算正样本图片的HOG特征
clog << "...[done]" << endl;
/**************************************************************************************************************
5、计算正样本2 HOG特征
****************************************************************************************************************/
//clog << "Histogram of Gradients are being calculated for positive images...";
//computeHOGs(pos_image_size, pos_lst_2, gradient_lst); //计算正样本图片的HOG特征
//clog << "...[done]" << endl;
/**************************************************************************************************************
6、计算负样本 HOG特征
****************************************************************************************************************/
clog << "Histogram of Gradients are being calculated for negative images...";
computeHOGs(pos_image_size, neg_lst, gradient_lst); //计算负样本图片的HOG特征
clog << "...[done]" << endl;
/**************************************************************************************************************
7、训练
****************************************************************************************************************/
Mat train_data;
convert_to_ml(gradient_lst, train_data); //转化为ml所需的训练数据形式
clog << "Training SVM...";
Ptr< SVM > svm = SVM::create(); /* Default values to train SVM */
svm->setCoef0(0.0);
svm->setDegree(3);
svm->setTermCriteria(TermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 1000, 1e-3));
svm->setGamma(0);
svm->setKernel(SVM::LINEAR);
//采用线性核函,其他的sigmoid 和RBF 可自行设置,其值由0-5。
svm->setNu(0.5);
svm->setP(0.1); // for EPSILON_SVR, epsilon in loss function?
svm->setC(0.01); // From paper, soft classifier
//svm->setType(SVM::C_SVC); // C_SVC; // EPSILON_SVR; // may be also NU_SVR; // do regression task
svm->setType(SVM::EPS_SVR); // C_SVC; // EPSILON_SVR; // may be also NU_SVR; // do regression task
svm->train(train_data, ROW_SAMPLE, Mat(labels));
clog << "...[done]" << endl;
vector< float > hog_detector; //定义hog检测器
get_svm_detector(svm, hog_detector); //得到训练好的检测器
HOGDescriptor hog; hog.winSize = pos_image_size; //窗口大小
hog.setSVMDetector(hog_detector);
hog.save(obj_det_filename); //保存分类器
//test_trained_detector(obj_det_filename, test_dir, videofilename); //检测训练集
#endif
return 0;
}