HOG+SVM实现车辆识别

HOG+SVM 实现车辆识别

做了一个车辆检测的小demo,熟悉流程~

说明:最开始使用裁剪好的数据集,训练后发现效果很差,所以自己裁剪数据集进行训练,效果更好一些

1、数据集下载

数据集采用了Visdrone2018数据集(本来是给YOLO3准备的【手动表情】)
数据下载的主页:http://www.aiskyeye.com/my/downloadD
在本次训练中,只用到了Task1:Object Detection in Images的部分实验数据:Trainset(1.44GB)
在这里插入图片描述

2、数据裁剪

训练时需要正样本和负样本,因为裁剪效果好一些,所以自己动手吧!检测的尺寸一共有2种,一种是64 * 128,一种是64 * 64,这里我选择64 * 64的尺寸,裁剪正样本为检测目标(这里为车辆),负样本为随机背景

裁剪工具:ImageCropper
裁剪时把裁剪尺寸设为64 * 64,但由于放缩实际裁剪大小并不是64 * 64,所以要对裁剪图片进行统一缩放:

	string data_path = "E:/车辆跟随项目/车辆检测/dym_car/hard1/hard1.txt";
	ifstream input_data(data_path);
	vector<string> data_sample_path;
	string str;
	int data_num;
	while (getline(input_data, str))  data_sample_path.push_back(str);
	data_num = data_sample_path.size();	
	input_data.close();
	for (int i = 0; i < data_num; ++i)
	{
		cout << i << endl;
		Mat src = imread(data_sample_path[i], 0);
		Mat dst = Mat::zeros(64, 64, CV_8UC3);   //8位无符号3通道
		resize(src, dst, dst.size());
		imwrite(data_sample_path[i], dst);
	}

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

3、批处理小功能

这里补充一下一个批处理小方法,因为要对文件夹中所有图片处理,所以要得到包含所有图片名称的.txt文件
(1)建立一个.txt文件,任意命名,如a.txt;
(2)在其中写入;

@echo off 
dir /s/b *.* > b.txt exit

b.txt就是你要生成的所有图片名称的文件;
(3)把a.txt移入图片所在文件夹;
(4)将a.txt另存为a.bat(可以直接改后缀,也可以另存为—a.bat—所有文件—保存);
(5)双击a.bat文件,这时候就可以得到b.txt了,注意删掉不必要的文件名称(如a.txt,a.bat,b.txt);

4、训练样本

最初始的训练非常简单,只有200个正样本和100个负样本(裁数据太麻烦啦),效果非常不好,后来加入了困难样本100个二次训练,目前还没加二次正样本训练,但是效果好了那么一丢丢,困难样本制作就是把误检的框框作为负样本训练:

	string pos_path = "E:/车辆跟随项目/车辆检测/dym_car/pos1/pos1.txt";
	string neg_path = "E:/车辆跟随项目/车辆检测/dym_car/neg1/neg1.txt";
	string hard_path = "E:/车辆跟随项目/车辆检测/dym_car/hard1/hard1.txt";//*
	Mat sample_feature_mat, sample_label_mat;
	ifstream input_pos_sample(pos_path);
	ifstream input_neg_sample(neg_path);
	ifstream input_hard_sample(hard_path);//*
	vector<string> pos_sample_path, neg_sample_path, hard_sample_path;//*
	////HOG描述子的维数,由图片大小、检测窗口大小、块大小、细胞单元中直方图bin个数决定
	int feature_dim;

	string str;
	int pos_sample_num, neg_sample_num, hard_sample_num;//*
	while (getline(input_pos_sample, str))  pos_sample_path.push_back(str);
	while (getline(input_neg_sample, str))  neg_sample_path.push_back(str);
	while (getline(input_hard_sample, str))  hard_sample_path.push_back(str);//*
	pos_sample_num = pos_sample_path.size();
	neg_sample_num = neg_sample_path.size();
	hard_sample_num = hard_sample_path.size();//*
	input_pos_sample.close();
	input_neg_sample.close();
	input_hard_sample.close();//*
	//HOG检测器,用来计算HOG描述子的
	//检测窗口(64,64),块尺寸(16,16),块步长(8,8),cell尺寸(8,8),直方图bin个数9
	HOGDescriptor *hog = new HOGDescriptor(Size(64, 64), Size(16, 16), Size(8, 8), Size(8, 8), 9);
	
	//正样本hog特征提取
	cout << "正样本:" << endl;
	for (int i = 0; i < pos_sample_num; ++i) {
		cout << i << endl;
		Mat input_img = imread(pos_sample_path[i], 0);
		Mat train_data(64, 64, CV_32FC1);
		resize(input_img, train_data, Size(64, 64));
		vector<float>descriptor;
		hog->compute(train_data, descriptor, Size(8, 8));
		if (i == 0) {
			feature_dim = descriptor.size();
			sample_feature_mat = Mat::zeros(pos_sample_num + neg_sample_num + hard_sample_num, feature_dim, CV_32FC1);//*
			sample_label_mat = Mat::zeros(pos_sample_num + neg_sample_num + hard_sample_num, 1, CV_32SC1);//*
		}
		float *pf = sample_feature_mat.ptr<float>(i);
		int *pl = sample_label_mat.ptr<int>(i);
		for (int j = 0; j < feature_dim; ++j) {
			*pf++ = descriptor[j];
		}
		*pl++ = 1;
	}
	//负样本hog特征提取
	cout << "负样本:" << endl;
	for (int i = 0; i < neg_sample_num; ++i) {
		cout << i << endl;
		Mat input_img = imread(neg_sample_path[i], 0);
		Mat train_data(64, 64, CV_32FC1);
		resize(input_img, train_data, Size(64, 64));
		vector<float>descriptor;
		hog->compute(train_data, descriptor, Size(8, 8));
		float *pf = sample_feature_mat.ptr<float>(i + pos_sample_num);
		int *pl = sample_label_mat.ptr<int>(i + pos_sample_num);
		for (int j = 0; j < feature_dim; ++j) {
			*pf++ = descriptor[j];
		}
		*pl++ = -1;
	}
	//HardExample负样本//*
	cout << "HardExample样本" << endl;
	for (int i = 0; i < hard_sample_num ; i++)
	{
		cout << i << endl;
		Mat input_img = imread(hard_sample_path[i], 0);
		Mat train_data(64, 64, CV_32FC1);
		resize(input_img, train_data, Size(64, 64));
		vector<float>descriptor;
		hog->compute(train_data, descriptor, Size(8, 8));
		float *pf = sample_feature_mat.ptr<float>(i + pos_sample_num + neg_sample_num);
		int *pl = sample_label_mat.ptr<int>(i + pos_sample_num + neg_sample_num);
		for (int j = 0; j < feature_dim; ++j) {
			*pf++ = descriptor[j];
		}
		*pl++ = -1;
	}

	//训练数据
	Ptr < SVM > svm = SVM::create();
	svm->setType(SVM::C_SVC);
	svm->setKernel(SVM::LINEAR);

	svm->setDegree(0);
	svm->setGamma(1);
	svm->setCoef0(0);
	svm->setC(1);//惩罚参数
	svm->setNu(0);
	svm->setP(0);
	svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 3000, 1e-6));//迭代次数和误差

	Ptr<TrainData> tData = TrainData::create(sample_feature_mat, ROW_SAMPLE, sample_label_mat);
	cout << "train begin" << endl;
	svm->trainAuto(tData);
	svm->save("E:/车辆跟随项目/车辆检测/dym_car/SVM_Mode2.xml"); //训练结果保存文件
	cout << "train done" << endl;

最终得到的.xml文件就是训练出来的模型

5、模型检测

接下来就是用训练好的模型做检测啦:

//加载SVM模型
	Ptr<SVM> svm = SVM::load("E:/车辆跟随项目/车辆检测/dym_car/SVM_Mode2.xml"); 
	if (svm->empty()) { //empty()函数 字符串是空的话返回是true
		cout << "读取XML文件失败。" << endl;
		return 1;
	}
	else {
		cout << "读取XML文件成功。" << endl;
	}


	Mat svecsmat = svm->getSupportVectors();//svecsmat元素的数据类型为float

	int svdim = svm->getVarCount();

	int numofsv = svecsmat.rows;

	Mat alphamat = Mat::zeros(numofsv, svdim, CV_32F);//alphamat和svindex必须初始化,否则getDecisionFunction()函数会报错
	Mat svindex = Mat::zeros(1, numofsv, CV_64F);

	Mat Result;
	double rho = svm->getDecisionFunction(0, alphamat, svindex);
	alphamat.convertTo(alphamat, CV_32F);//将alphamat元素的数据类型重新转成CV_32F

	cout << "1" << endl;
	Result = -1 * alphamat * svecsmat;//float
	cout << "2" << endl;

	vector<float> vec;
	for (int i = 0; i < svdim; ++i)
	{
		vec.push_back(Result.at<float>(0, i));
	}
	vec.push_back(rho);

	//保存HOG检测的文件
	ofstream fout("HOGDetectorForOpenCV.txt");
	for (int i = 0; i < vec.size(); ++i)
	{
		fout << vec[i] << endl;
	}
	cout << "保存完毕" << endl;

	//----------读取图片进行检测----------------------------
	//  HOGDescriptor hog_test;
	HOGDescriptor hog_test(Size(64, 64), Size(16, 16), Size(8, 8), Size(8, 8), 9);
	hog_test.setSVMDetector(vec);

	Mat src = imread("E:/车辆跟随项目/车辆检测/dym_car/1.jpg", 0);
	
	if (!src.data) {
		cout << "测试图片读取失败" << endl;
		return 1;
	}
	vector<Rect> found, found_filtered;

	int p = 1;
	resize(src, src, Size(src.cols / p, src.rows / p));

	clock_t startTime, finishTime;
	cout << "开始检测" << endl;

	startTime = clock();                                                //1.05
	hog_test.detectMultiScale(src, found, 0, Size(8, 8), Size(32, 32), 1.05, 2);   //多尺度检测
	finishTime = clock();
	cout << "检测所用时间为" << (finishTime - startTime)*1.0 / CLOCKS_PER_SEC << " 秒 " << endl;

	cout << endl << "矩形框的尺寸为 : " << found.size() << endl;

	//找出所有没有嵌套的矩形,并放入found_filtered中,如果有嵌套的话,则取外面最大的那个矩形放入found_filtered中
	for (int i = 0; i < found.size(); i++)
	{
		Rect r = found[i];
		int j = 0;
		for (; j < found.size(); j++)
			if (j != i && (r & found[j]) == r)
				break;
		if (j == found.size())
			found_filtered.push_back(r);
	}
	cout << endl << "嵌套矩形框合并完毕" << endl;

	//画矩形框,因为hog检测出的矩形框比实际的框要稍微大些,所以这里需要做一些调整
	for (int i = 0; i<found_filtered.size(); i++)
	{
		Rect r = found_filtered[i];

		r.x += cvRound(r.width*0.1); //int cvRound(double value) 对一个double型的数进行四舍五入,并返回一个整型数!
		r.width = cvRound(r.width*0.8);
		r.y += cvRound(r.height*0.07);
		r.height = cvRound(r.height*0.8);

		rectangle(src, r.tl(), r.br(), Scalar(0, 0, 255), 3);
	}

	imwrite("E:/车辆跟随项目/车辆检测/dym_car/12.jpg", src);
	namedWindow("src", 0);
	imshow("src", src);
	waitKey(0);

初始训练效果(框框满天飞脑阔疼):
在这里插入图片描述增加困难样本(好了那么一丢丢)
在这里插入图片描述

6、总结

(1)由于只是熟悉下流程,检测效果一般般,也没有测试;
(2)方向一:增加数据集数量;
(3)方向二:制作二次训练正样本(该检测没检测出来);

7、参考

https://www.jianshu.com/p/49d029f1b489
https://blog.csdn.net/qq_37487118/article/details/83046962
https://blog.csdn.net/yang1688899/article/details/81225668?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://bbs.csdn.net/topics/391950597?list=lz
https://blog.csdn.net/u010869312/article/details/44927721
https://www.cnblogs.com/heleifz/p/train-hog-svm-detector.html
https://www.it610.com/article/5135995.htm
https://blog.csdn.net/aa997749935/article/details/88354355

发布了26 篇原创文章 · 获赞 0 · 访问量 1206

猜你喜欢

转载自blog.csdn.net/weixin_44264994/article/details/104612420