1.hog_svm.h,各个函数的声明
#ifndef HOG_SVM_H
#define HOG_SVM_H
#include
#include
#include
#include //机器学习
#include
#include
#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 read_image_in_folder(cv::String pattern); //遍历文件夹
cv::Mat sample_hog(vectorimages); //单图像的hog特征
vector 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 model_detect(const char *model);
void draw_rectangle(Mat img, vectorfound); //可视化
void hard_example(string pattern, string savename); //难例样本
};
#endif
2.hog_svm.cpp,各个函数的实现
#include "hog_svm.h"
vector My_svm::read_image_in_folder(cv::String pattern) { //遍历文件夹
vectorfn;
glob(pattern, fn, false);
vectorimages;
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(vectorimages) { //遍历文件夹内的所有的图像,求整体的hog特征
Mat sample_feature_mat;
for (int i = 0; i < images.size(); i++)
{
Mat img = images.at(i);
vector 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转为Mat类型
{
sample_feature_mat.at(i, j) = feature[j];
}
}
return sample_feature_mat;
}
vector My_svm::caculate_hog(Mat img) { //计算hog特征
Mat grayimg, hogimg, single_feat;
cvtColor(img, grayimg, COLOR_BGR2GRAY);
resize(grayimg, hogimg, Size(64, 128));
vectordescriptors;
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(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 pos_imgs = read_image_in_folder(pos_pattern);
vectorneg_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 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 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 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;
vectorsvm_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(0, i) = svm_alpha[i];
}
result_mat = -1 * alpha_mat * support_vector_mat;
vectormy_detector;
//将result_mat中的数据复制到数组my_detector中
for (int i = 0; i < descriptor_dim; i++)
{
my_detector.push_back(result_mat.at(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, vectorfound) {
vectorfound_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 imgs;
vectorfn;
My_svm my_svm;
glob(pattern, fn, true);
vectormy_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);
vectorfound; //矩形框数组
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
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); //训练模型并保存
//加载模型,生成检测子
vectormy_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);
vectorfound; //矩形框数组
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;
}