百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

opencv3/4 svm+hog训练自己的数据集——附源码

bigegpt 2024-08-19 12:03 3 浏览

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


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

  1. 话不多说,先上效果图

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

一、训练准备

训练集及测试集:
链接: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;
}

更多的效果图

相关推荐

悠悠万事,吃饭为大(悠悠万事吃饭为大,什么意思)

新媒体编辑:杜岷赵蕾初审:程秀娟审核:汤小俊审签:周星...

高铁扒门事件升级版!婚宴上‘冲喜’老人团:我们抢的是社会资源

凌晨两点改方案时,突然收到婚庆团队发来的视频——胶东某酒店宴会厅,三个穿大红棉袄的中年妇女跟敢死队似的往前冲,眼瞅着就要扑到新娘的高额钻石项链上。要不是门口小伙及时阻拦,这婚礼造型团队熬了三个月的方案...

微服务架构实战:商家管理后台与sso设计,SSO客户端设计

SSO客户端设计下面通过模块merchant-security对SSO客户端安全认证部分的实现进行封装,以便各个接入SSO的客户端应用进行引用。安全认证的项目管理配置SSO客户端安全认证的项目管理使...

还在为 Spring Boot 配置类加载机制困惑?一文为你彻底解惑

在当今微服务架构盛行、项目复杂度不断攀升的开发环境下,SpringBoot作为Java后端开发的主流框架,无疑是我们手中的得力武器。然而,当我们在享受其自动配置带来的便捷时,是否曾被配置类加载...

Seata源码—6.Seata AT模式的数据源代理二

大纲1.Seata的Resource资源接口源码2.Seata数据源连接池代理的实现源码3.Client向Server发起注册RM的源码4.Client向Server注册RM时的交互源码5.数据源连接...

30分钟了解K8S(30分钟了解微积分)

微服务演进方向o面向分布式设计(Distribution):容器、微服务、API驱动的开发;o面向配置设计(Configuration):一个镜像,多个环境配置;o面向韧性设计(Resista...

SpringBoot条件化配置(@Conditional)全面解析与实战指南

一、条件化配置基础概念1.1什么是条件化配置条件化配置是Spring框架提供的一种基于特定条件来决定是否注册Bean或加载配置的机制。在SpringBoot中,这一机制通过@Conditional...

一招解决所有依赖冲突(克服依赖)

背景介绍最近遇到了这样一个问题,我们有一个jar包common-tool,作为基础工具包,被各个项目在引用。突然某一天发现日志很多报错。一看是NoSuchMethodError,意思是Dis...

你读过Mybatis的源码?说说它用到了几种设计模式

学习设计模式时,很多人都有类似的困扰——明明概念背得滚瓜烂熟,一到写代码就完全想不起来怎么用。就像学了一堆游泳技巧,却从没下过水实践,很难真正掌握。其实理解一个知识点,就像看立体模型,单角度观察总...

golang对接阿里云私有Bucket上传图片、授权访问图片

1、为什么要设置私有bucket公共读写:互联网上任何用户都可以对该Bucket内的文件进行访问,并且向该Bucket写入数据。这有可能造成您数据的外泄以及费用激增,若被人恶意写入违法信息还可...

spring中的资源的加载(spring加载原理)

最近在网上看到有人问@ContextConfiguration("classpath:/bean.xml")中除了classpath这种还有其他的写法么,看他的意思是想从本地文件...

Android资源使用(android资源文件)

Android资源管理机制在Android的开发中,需要使用到各式各样的资源,这些资源往往是一些静态资源,比如位图,颜色,布局定义,用户界面使用到的字符串,动画等。这些资源统统放在项目的res/独立子...

如何深度理解mybatis?(如何深度理解康乐服务质量管理的5个维度)

深度自定义mybatis回顾mybatis的操作的核心步骤编写核心类SqlSessionFacotryBuild进行解析配置文件深度分析解析SqlSessionFacotryBuild干的核心工作编写...

@Autowired与@Resource原理知识点详解

springIOCAOP的不多做赘述了,说下IOC:SpringIOC解决的是对象管理和对象依赖的问题,IOC容器可以理解为一个对象工厂,我们都把该对象交给工厂,工厂管理这些对象的创建以及依赖关系...

java的redis连接工具篇(java redis client)

在Java里,有不少用于连接Redis的工具,下面为你介绍一些主流的工具及其特点:JedisJedis是Redis官方推荐的Java连接工具,它提供了全面的Redis命令支持,且...