c语言版本opencv3/4 利用svm+hog训练自己的数据集——仪表盘的检测

c语言版本opencv3/4 利用svm+hog训练自己的数据集——仪表盘的检测


项目背景:最近在做一个机器人巡检仪表盘的项目,需要识别众多的仪表盘并读数。因此需要用svm识别出表盘大体位置再进行摆盘示数的识别。


2020.10.25更新

改进思路

性能——将图片缩放到400*300时,耗时为:789毫秒

  • 1、为了降低耗时,可以将图片转换成黑白图进行训练及识别。且负样本训练集也应该由最终送入检测器hog.detectMultiScale(test_img, detections, foundWeights)的宽高进行裁剪众多128*128小块。
  • 2、考虑多线程,一个读图送图,一个识别。
    目标:尽量能达到5-10帧即可。

2020.10.24初版

话不多说,先上效果图

在这里插入图片描述

在这里插入图片描述
训练的图片比较少,因此检测框有些许的歪斜。可以增加图片达到更准确的检测效果

一、训练准备

训练集及测试集:
链接:https://pan.baidu.com/s/19m0-WSNqWYYc0U94tAUyog
提取码:rcoc
复制这段内容后打开百度网盘手机App,操作更方便哦

路径位置:
在这里插入图片描述
正样本是128128的仪表图片,如下图:
在这里插入图片描述
负样本是从整张图片集合中裁剪的128
128的图片:
在这里插入图片描述
下面是将最终要识别的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
* 作者:diyun
* 版本: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
* 作者:diyun
* 版本: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;
}

更多的效果图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翟羽嚄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值