hog svm图像检测--VS2017(C++)

这个博客介绍了如何使用C++实现基于HOG特征和SVM的物体检测。作者首先定义了`My_svm`类,包含了读取图像、计算HOG特征、生成标签、合并样本等功能。接着,详细展示了从正负样本中提取特征、训练SVM模型的过程,并提供了模型检测和绘制检测结果矩形框的函数。最后,主函数演示了模型的应用,包括加载模型、生成检测子和进行难例样本检测。
摘要由CSDN通过智能技术生成

1.hog_svm.h,各个函数的声明

#ifndef HOG_SVM_H
#define HOG_SVM_H

#include<opencv2/opencv.hpp>
#include <iostream>
#include <fstream>
#include <opencv2/ml.hpp>  //机器学习
#include<opencv2/core.hpp>
#include <opencv2/highgui.hpp>

#define single_sample_number 9000
#define pos_number  9000  //正样本数
#define neg_number 9000  //负样本数
#define hard_number          //难例样本数

using namespace cv;
using namespace std;

class My_svm
{
public:
	vector<Mat> read_image_in_folder(cv::String pattern);  //遍历文件夹
	cv::Mat  sample_hog(vector<Mat>images);      //单图像的hog特征
	vector<float> caculate_hog(Mat img);   //文件夹内所有图像的Hog特征
	cv::Mat sample_label(Mat feature, int number);  // 生成标签
	cv::Mat caculate_concat(Mat feature1, Mat feature2);  // 将正负样本,正负标签合并在一起
	void hog_svm(cv::String pos_pattern, cv::String neg_pattern);
	void svm_train(Mat feature, Mat label);  // 训练svm
	vector<float> model_detect(const char *model);
	void draw_rectangle(Mat img, vector<Rect>found);  //可视化
	void hard_example(string pattern, string savename);		//难例样本

};
#endif

2.hog_svm.cpp,各个函数的实现

#include "hog_svm.h"

vector<Mat> My_svm::read_image_in_folder(cv::String pattern) {  //遍历文件夹
	vector<cv::String>fn;
	glob(pattern, fn, false);
	vector<Mat>images;
	size_t count = fn.size();
	for (size_t i = 0; i < count; i++) {
		images.push_back(imread(fn[i]));  //尾部插入变量
		if (i % 1000 == 0)
		{
			cout << i << endl;
		}
		// 		imshow("img", imread(fn[i]));
		// 		waitKey(1);
	}
	return images;
}
cv::Mat My_svm::sample_hog(vector<Mat>images) {  //遍历文件夹内的所有的图像,求整体的hog特征
	Mat sample_feature_mat;
	for (int i = 0; i < images.size(); i++)
	{
		Mat img = images.at(i);
		vector<float> feature;
		feature = caculate_hog(img);   
		if (i==0)
		{                                                        //行数等于样本总数,列数等于特征维度
			sample_feature_mat = Mat::zeros(single_sample_number, feature.size(), CV_32FC1);
		}
		for (int j=0; j<feature.size(); j++)  //将vector<Mat>转为Mat类型
		{
			sample_feature_mat.at<float>(i, j) = feature[j];  
		}
	}
	return sample_feature_mat;
}
vector<float> My_svm::caculate_hog(Mat img) {  //计算hog特征
	Mat  grayimg, hogimg, single_feat;
	cvtColor(img, grayimg, COLOR_BGR2GRAY);
	resize(grayimg, hogimg, Size(64, 128));
	vector<float>descriptors;
	HOGDescriptor hog;
	hog.compute(hogimg, descriptors);
	return descriptors;
}
cv::Mat My_svm::sample_label(Mat feature, int number) {
	Mat sample_labels;
	sample_labels = Mat::zeros(single_sample_number, 1, CV_32SC1);
	for (int num = 0; num < single_sample_number; num++)
	{
		sample_labels.at<float>(num, 0) = number;
	}
	return sample_labels;
}
cv::Mat My_svm::caculate_concat(Mat feature1, Mat feature2) {
	Mat all_feature = Mat::zeros(pos_number + neg_number, feature1.cols, CV_32FC1);
	vconcat(feature1, feature2, all_feature);  //左右拼接,mat的行列与正常的相反
	return all_feature;
}


void My_svm::hog_svm(cv::String pos_pattern, cv::String neg_pattern) {
	vector<Mat> pos_imgs = read_image_in_folder(pos_pattern);
	vector<Mat>neg_imgs = read_image_in_folder(neg_pattern);
	if (pos_imgs.empty() or neg_imgs.empty())
	{
		cout << "load images failed!" << endl;
		return;
	}
	clock_t start, end;
	start = clock();
	//计算正负样本特征
	Mat pos_feature, neg_feature;
	pos_feature = sample_hog(pos_imgs);
	neg_feature = sample_hog(neg_imgs);
	//添加正负样本标签
	Mat pos_label, neg_label;
	pos_label = sample_label(pos_feature, 1);
	neg_label = sample_label(neg_feature, 0);
	//总特征,总标签
	Mat all_features, all_labels;
	all_features = caculate_concat(pos_feature, neg_feature);
	all_labels = caculate_concat(pos_label, neg_label);

	end = clock();
	cout << "The obtain hog feature run time is :" << (double)(end - start) / CLOCKS_PER_SEC << "s" << endl;
	//训练svm模型,保存为xml文件
	svm_train(all_features, all_labels);
}
void My_svm::svm_train(Mat feature, Mat label) {
	//配置svm模型参数--opencv3中svm的使用
	clock_t start, end;
	start = clock();
	Ptr<ml::SVM> svm;
	svm = ml::SVM::create();
	svm->setType(ml::SVM::C_SVC);  //svm的类型
	svm->setKernel(ml::SVM::LINEAR);  //核函数
	svm->setDegree(0);   //degree
	svm->setGamma(1);  //gamma
	svm->setCoef0(0);  //核函数常数项
	svm->setC(1);  //C
	svm->setNu(0);
	svm->setP(0);  //epsilon
	svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 0.01));  //设置或获取训练时迭代中止条件

	cout << "Training svm..." << endl;
	//svm->train(feature, ml::ROW_SAMPLE, label);  //训练样本的数据类型必须是CV_32FC1,标签必须是或CV_32SC1
	Ptr<ml::TrainData> traindata;
	traindata = ml::TrainData::create(feature, ml::ROW_SAMPLE, label);
	svm->trainAuto(traindata);  //交叉验证次数,默认为10
	svm->save("svm_linear.xml");
	end = clock();
	cout << "SVM Train Finish!!!" << endl;
	cout << "The taing svm model run time is :" << (double)(end - start) / CLOCKS_PER_SEC << "s" << endl;
}
vector<float> My_svm::model_detect(const char *model) {
	Ptr < ml::SVM > svm = ml::SVM::load(model);
	clock_t start, end;
	start = clock();
	//加载模型参数
	int descriptor_dim = svm->getVarCount();  //特征向量维度
	Mat support_vector;
	support_vector = svm->getSupportVectors();  //支持向量的个数
	int support_vector_number = support_vector.rows;
	cout << "支持向量个数:" << support_vector_number << endl;

	//由模型参数计算HOG的检测子
	Mat alpha_mat;
	float svm_rho;
	vector<float>svm_alpha, svm_svidx;
	svm_rho = svm->getDecisionFunction(0, svm_alpha, svm_svidx);  //决策函数
	alpha_mat = Mat::zeros(1, support_vector_number, CV_32FC1);  //alpha向量
	Mat support_vector_mat, result_mat;
	support_vector_mat = Mat::zeros(support_vector_number, descriptor_dim, CV_32FC1);  //支持向量矩阵
	result_mat = Mat::zeros(1, descriptor_dim, CV_32FC1);  //alpha向量乘以支持向量矩阵
	support_vector_mat = support_vector;
	//将alpha向量的数据复制到alpha_mat中
	for (int i = 0; i < support_vector_number; i++)
	{
		alpha_mat.at<float>(0, i) = svm_alpha[i];
	}
	result_mat = -1 * alpha_mat * support_vector_mat;

	vector<float>my_detector;
	//将result_mat中的数据复制到数组my_detector中
	for (int i = 0; i < descriptor_dim; i++)
	{
		my_detector.push_back(result_mat.at<float>(0, i));
	}
	//添加偏移量rho,得到检测子
	my_detector.push_back(svm_rho);
	end = clock();
	cout << "检测子维数:" << my_detector.size() << endl;
	cout << "model create detector run time: " << (double)(end - start) / CLOCKS_PER_SEC << endl;
	return my_detector;
}
void My_svm::draw_rectangle(Mat img, vector<Rect>found) {
	vector<Rect>found_filtered;
	cout << "找到的矩形框的个数:" << found.size() << endl;
	for (int i = 0; i < found.size(); i++)  // 查看是否有嵌套的矩形框
	{
		Rect r = found[i];
		int j = 0;
		for (; j < found.size(); j++)    //for循环判断
			if (j != i && (r & found[j]) == r)
				break;
		if (j == found.size())
			found_filtered.push_back(r);
	}
	cout << "画矩形框" << endl;
	for (int i = 0; i < found_filtered.size(); i++)  //画矩形框
	{
		Rect r = found_filtered[i];
		rectangle(img, r.tl(), r.br(), Scalar(0, 0, 255), 5);
	}
	namedWindow("img", WINDOW_NORMAL);
	imshow("img", img);
	waitKey(0);
}

void My_svm::hard_example(string pattern, string savename){
	cout << "开始进行难例样本的检测:" << endl;
	clock_t start, end;
	vector<Mat> imgs;
	vector<String>fn;
	My_svm my_svm;
	glob(pattern, fn, true);
	vector<float>my_detector = my_svm.model_detect("svm1.xml");
	HOGDescriptor  my_hog;  //设置HOGDescriptor的检测子,进行测试
	my_hog.setSVMDetector(my_detector);
	cout << "开始循环测试图像" << endl;
	int num = 0;
	for (int i = 0; i < fn.size(); i++)
	{
		imgs.push_back(imread(fn[i]));
		Mat img = imgs[i];
		start = clock();
		// 		imshow("imgs", imgs[i]);
		// 		waitKey(2);
		vector<Rect>found;  //矩形框数组
		my_hog.detectMultiScale(img, found, 0, Size(16, 16), Size(16, 16), 1.05, 2);   //多尺度检测
		for (int j = 0; j < found.size(); j++)
		{
			Rect r = found[j];
			if (r.x < 0)
				r.x = 0;
			if (r.y < 0)
				r.y = 0;
			if (r.x + r.width > img.cols)
				r.width = img.cols - r.x;
			if (r.y + r.height > img.rows)
				r.height = img.rows - r.y;
			Mat hard_example_img = img(r);
			resize(hard_example_img, hard_example_img, Size(300, 170));
			// 			imshow("imgs", hard_example_img);
			// 			waitKey(2);
			savename = savename + to_string(num) + ".jpg";
			imwrite(savename, hard_example_img);
			end = clock();
			cout << "已经保存图像" << endl;
			cout << "保存图像所用时间" << (double)(end - start) / CLOCKS_PER_SEC << endl;
			num++;
		}
	}
}

3. main(),主函数的调用

#include "hog_svm.h"
#include <thread>


int main() {
	cv::String pos_pattern = "D:/2022/3月/HOG+SVM/hog-detector/positive_samples/*.jpg";
	cv::String neg_pattern = "D:/2022/3月/HOG+SVM/hog-detector/negative_samples/*.jpg";
	My_svm my_svm;
	my_svm.hog_svm(pos_pattern, neg_pattern);  //训练模型并保存

	//加载模型,生成检测子
	vector<float>my_detector = my_svm.model_detect("svm_linear.xml");
	HOGDescriptor  my_hog;  //设置HOGDescriptor的检测子,进行测试
	my_hog.setSVMDetector(my_detector);

	cout << "测试开始" << endl;
	Mat img = imread("D:/2022/3月/HOG+SVM/hog-detector/test_samples/0.jpg", 1);
	Mat gray_img;
	cvtColor(img, gray_img, COLOR_BGR2GRAY);
	vector<Rect>found;  //矩形框数组
	clock_t start, end;
	start = clock();
	cout << "开始运行时间:"<<(double)(start) / CLOCKS_PER_SEC << endl;
	my_hog.detectMultiScale(gray_img, found, 0, Size(16, 16), Size(16, 16), 1.03, 2);   //多尺度检测
	end = clock();
	cout << "运行结束时间:" << (double)(end) / CLOCKS_PER_SEC << endl;
	my_svm.draw_rectangle(img, found);  //画矩形框显示

	//hard examples
	string hard_pattern = "D:/2022/3月/HOG+SVM/hog-detector/hard_examples/*.jpg";
	string savename = "D:/2022/3月/HOG+SVM/hog-detector/hard_examples/";
	//my_svm.hard_example(hard_pattern, savename);
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值