opencv学习笔记(七)SVM+HOG

opencv学习笔记(七)SVM+HOG

一、简介

  方向梯度直方图(Histogram of Oriented Gradient,HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子。它通过计算和统计图像局部区域的梯度直方图来构成特征。Hog特征结合SVM分类器已经被广泛用于图像识别中,尤其在行人检测中获得了极大的成功。需要提醒的是,HOG+SVM进行行人检测的方法是法国研究院Dalal在2005的CVPR上提出的。

  最近在做车标识别相关的研究,用到了SVM+HOG的方法进行识别,下面的例子,使用的数据样本是6类车标:本田、大众、丰田、现代、马自达和雪铁龙。

二、SVM+HOG进行车标识别

  批处理:

  首先在训练样本和测试样本的文件夹下,使用dos批处理命令:

dir /b > trainsamsFilenameDecribeTxt.txt

dir /b > testsamsFilenameDecribeTxt.txt

  得到训练样本和测试样本的文件名列表,如下所示:

  

  注意将最后一行的“trainsamsFilenameDecribeTxt.txt”删掉。

  然后需要将训练样本和测试样本文件夹所在的路径加到上述文件名列表的前面,形成样本的完整路径。我使用如下代码帮助我完成,

  首先是训练样本:

 1 bool ClogoRecognition::createTrainSamDescribeTxt()
 2 {
 3     string s;
 4     ifstream in(DEFAULT_TRAINSAMPLES_FILESNAME_TXT_DECRIBE_PATH);
 5     if (!in)
 6         return FALSE;
 7     ofstream out;
 8     out.open(DEFAULT_TRAINSAMPLES_TXT_DECRIBE_PATH, ios::trunc); //ios::trunc表示在打开文件前将文件清空,由于是写入,文件不存在则创建
 9     while (getline(in, s))//逐行读取数据并存于s中,直至数据全部读取
10     {
11         out <<DEFAULT_TRAINSAMPLES_PATH<< s.c_str() << ‘\n‘;//路径后面加上训练样本的filename
12         int n = s.c_str()[0] - ‘0‘;//每个训练样本文件都以数字开头命令,数字即代表该文件的类别
13         out << n << ‘\n‘;//每个样本的后面写入其类别,用于SVM训练时指定type
14     }
15     in.close();
16     out.close();
17     return TRUE;
18 }

  

  运行结果:

  

  对于训练样本,路径之后紧接着该文件对应的标签类别。便于之后的训练步骤。

  其次是测试样本:

 1 /*创建测试样本描述文件*/
 2 bool ClogoRecognition::createTestSamDescribeTxt()
 3 {
 4     string s;
 5     ifstream in(DEFAULT_TESTSAMPLES_FILESNAME_TXT_DESCRIBE_PATH);
 6     if (!in)
 7         return FALSE;
 8     ofstream out;
 9     out.open(DEFAULT_TESTSAMPLES_TXT_DECRIBE_PATH, ios::trunc); //ios::trunc表示在打开文件前将文件清空,由于是写入,文件不存在则创建
10     while (getline(in, s))//逐行读取数据并存于s中,直至数据全部读取
11     {
12         out << DEFAULT_TESTSAMPLES_PATH << s.c_str() << ‘\n‘;//路径后面加上测试样本的filename
13     }
14     in.close();
15     out.close();
16     return TRUE;
17 }

  运行结果:

  

  样本图片和数量,第一行从左往右依次为:本田、大众、丰田;第二行从左往右一次为:现代、马自达、雪铁龙;

  SVM训练:

 1 bool ClogoRecognition::svmTrain()
 2 {
 3         vector<string> img_path;//图像路径容器
 4         vector<int> img_catg;//图像类别容器
 5         int nLine = 0;
 6         string buf;
 7         ifstream svm_data(DEFAULT_TRAINSAMPLES_TXT_DECRIBE_PATH);//训练样本图片的路径都写在这个txt文件中,使用bat批处理文件可以得到这个txt文件
 8         if (!svm_data)
 9             return FALSE;
10         unsigned long n;
11         while (svm_data)//将训练样本文件依次读取进来
12         {
13             if (getline(svm_data, buf))
14             {
15                 nLine++;
16                 if (nLine % 2 == 0)//注:奇数行是图片全路径,偶数行是标签
17                 {
18                     img_catg.push_back(atoi(buf.c_str()));//atoi将字符串转换成整型,标志(0,1,2,...,9),注意这里至少要有两个类别,否则会出错
19                 }
20                 else
21                 {
22                     img_path.push_back(buf);//图像路径
23                 }
24             }
25         }
26         svm_data.close();//关闭文件
27         CvMat *data_mat, *res_mat;
28         int nImgNum = nLine / 2; //nImgNum是样本数量,只有文本行数的一半,另一半是标签
29         data_mat = cvCreateMat(nImgNum, 432, CV_32FC1);  //第二个参数,即矩阵的列是由下面的descriptors的大小决定的,可以由descriptors.size()得到,且对于不同大小的输入训练图片,这个值是不同的
30         cvSetZero(data_mat);
31         //类型矩阵,存储每个样本的类型标志
32         res_mat = cvCreateMat(nImgNum, 1, CV_32FC1);
33         cvSetZero(res_mat);
34         IplImage* src;
35         IplImage* trainImg = cvCreateImage(cvSize(40, 32), 8, 3);//需要分析的图片,这里车标的尺寸归一化至40*32,所以上面定义了432,如果要更改图片大小,可以先用debug查看一下descriptors是多少,然后设定好再运行
36
37         //处理HOG特征
38         for (string::size_type i = 0; i != img_path.size(); i++)
39         {
40             src = cvLoadImage(img_path[i].c_str(), 1);
41             if (src == NULL)
42             {
43                 cout << " can not load the image: " << img_path[i].c_str() << endl;
44                 continue;
45             }
46
47             cout << " 处理: " << img_path[i].c_str() << endl;
48
49             cvResize(src, trainImg);
50             HOGDescriptor *hog = new HOGDescriptor(cvSize(40, 32), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9);//图片尺寸:40*32;block尺寸:16*16;cell尺寸:8*8;检测窗口的滑动步长:8*8;一个单元格内统计9个方向的梯度直方图
51             vector<float>descriptors;//存放结果
52             hog->compute(trainImg, descriptors, Size(1, 1), Size(0, 0)); //Hog特征计算
53             cout << "HOG dims: " << descriptors.size() << endl;
54             n = 0;
55             for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++)
56             {
57                 cvmSet(data_mat, i, n, *iter);//存储HOG特征
58                 n++;
59             }
60             cvmSet(res_mat, i, 0, img_catg[i]);
61             cout << " 处理完毕: " << img_path[i].c_str() << " " << img_catg[i] << endl;
62         }
63
64
65         //    CvSVM svm = CvSVM();//新建一个SVM
66         CvSVM svm;
67         CvSVMParams param;//这里是SVM训练相关参数
68         CvTermCriteria criteria;
69         criteria = cvTermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON);
70         param = CvSVMParams(CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.09, 1.0, 10.0, 0.5, 1.0, NULL, criteria);
71 //        param = CvSVMParams(CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.3, 1.0, 5, 0.5, 1.0, NULL, criteria);
72         svm.train(data_mat, res_mat, NULL, NULL, param);//训练数据
73         //保存训练好的分类器
74         svm.save(DEFAULT_SVMMODEL_PATH);
75         cvReleaseMat(&data_mat);
76         cvReleaseMat(&res_mat);
77         cvReleaseImage(&trainImg);
78         return TRUE;
79 }

  等待几分钟即可得到训练好的xml模型;

  SVM测试:

 1 bool ClogoRecognition::svmTest()
 2 {
 3     string buf;
 4     CvSVM svm;
 5     svm.load(DEFAULT_SVMMODEL_PATH);//加载训练好的xml文件
 6     //检测样本
 7     IplImage *test;
 8     char result[512];
 9     vector<string> img_tst_path;
10     ifstream img_tst(DEFAULT_TESTSAMPLES_TXT_DECRIBE_PATH);  //加载需要预测的图片集合,这个文本里存放的是图片全路径,不要标签
11     if (!img_tst)
12         return FALSE;
13     while (img_tst)
14     {
15         if (getline(img_tst, buf))
16         {
17             img_tst_path.push_back(buf);
18         }
19     }
20     img_tst.close();
21
22     ofstream predict_txt(DEFAULT_TESTSAMPLES_RECOGNITION_RESULT_TXT_DECRIBE_PATH);//把预测结果存储在这个文本中
23     for (string::size_type j = 0; j != img_tst_path.size(); j++)//依次遍历所有的待检测图片
24     {
25         test = cvLoadImage(img_tst_path[j].c_str(), 1);
26         if (test == NULL)
27         {
28             cout << " can not load the image: " << img_tst_path[j].c_str() << endl;
29             continue;//结束本次循环
30         }
31         IplImage* trainTempImg = cvCreateImage(cvSize(40, 32), 8, 3);
32         cvZero(trainTempImg);
33         cvResize(test, trainTempImg);
34         HOGDescriptor *hog = new HOGDescriptor(cvSize(40, 32), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9);
35         vector<float>descriptors;//结果数组
36         hog->compute(trainTempImg, descriptors, Size(1, 1), Size(0, 0));
37         cout << "HOG dims: " << descriptors.size() << endl;
38         CvMat* SVMtrainMat = cvCreateMat(1, descriptors.size(), CV_32FC1);
39         int n = 0;
40         for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++)
41         {
42             cvmSet(SVMtrainMat, 0, n, *iter);
43             n++;
44         }
45
46         int ret = svm.predict(SVMtrainMat);//检测结果
47         sprintf(result, "%s  %d\r\n", img_tst_path[j].c_str(), ret);
48         predict_txt << result;  //输出检测结果到文本
49     }
50     predict_txt.close();
51     cvReleaseImage(&test);
52     return TRUE;
53 }

  

  运行SVM测试代码后,运行结果写入指定的txt中,每一行的最后一个数字代表该行路径下的图片的识别结果。如下图所示:

  

  图片文件名中第一个数字代表其类别,当和该行中最后一个数字一致时,说明识别正确,否则识别错误。由图中可以看到,识别结果还是挺不错的。

  

  

  

  

时间: 2024-10-16 00:17:56

opencv学习笔记(七)SVM+HOG的相关文章

OpenCv学习笔记(七)---OpenCv中的基本绘图函数,圆,椭圆,线段,矩形,多边形的绘制(1)

(一)本节教程的目的 本节你将学到: 1--如何使用Point在图像中定义2D点 2--如何以及为何使用Scalar 3--用OpenCv的函数Line绘直线 4--用OpenCvd的函数ellipse绘制椭圆 5--用OpenCv的函数rectangle绘矩形 6--用OpenCv的函数circle绘圆 7--用OpenCv的函数fillPoly绘填充多边形 (二)原理,本节我们将大量使用Point和Scalar这两个结构: **********************************

第十七篇:博采众长--初探WDDM驱动学习笔记(七)

基于WDDM驱动的DirectX视频加速重定向框架设计与实现 现在的研究生的论文, 真正质量高的, 少之又少, 开题开得特别大, 动不动就要搞个大课题, 从绪论开始到真正自己所做的内容之间, 是东拼西凑地抄概念, 抄公式, 达到字数篇幅的要求, 而自己正真做了什么, 有哪些实际感受, 做出的内容, 相比前面的东拼西凑就几点内容, 之后就草草结束, 步入感谢的段落. 原因不光只有学生自己, 所谓的读研, 如果没有一个环境, 学生有再大的愿望, 再强的毅力, 到头来也只是空无奈. 有些导师要写书,

马哥学习笔记七——LAMP编译安装之MYSQL

1.准备数据存放的文件系统 新建一个逻辑卷,并将其挂载至特定目录即可.这里不再给出过程. 这里假设其逻辑卷的挂载目录为/mydata,而后需要创建/mydata/data目录做为mysql数据的存放目录. 2.新建用户以安全方式运行进程: # groupadd -r mysql # useradd -g mysql -r -s /sbin/nologin -M -d /mydata/data mysql # chown -R mysql:mysql /mydata/data 3.安装并初始化my

Opencv学习笔记(六)SURF学习笔记

原创文章,转载请注明出处:http://blog.csdn.net/crzy_sparrow/article/details/7392345 本人挺菜的,肯定有非常多错误纰漏之处 ,希望大家不吝指正. 看了harris角点检測之后,開始研究SURF角点检測,发现挺复杂的,一时也仅仅了解了大概,把了解的东西总结下,以便下次深入学习. SURF角点检測算法是对SIFT的一种改进,主要体如今速度上,效率更高.它和SIFT的主要差别是图像多尺度空间的构建方法不同. 在计算视觉领域,尺度空间被象征性的表述

Lua学习笔记(七):迭代器与泛型for

1.迭代器与闭包 迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素.在Lua中我们常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素. 迭代器需要保留上一次成功调用的状态和下一次成功调用的状态,也就是他知道来自于哪里和将要前往哪里.闭包提供的机制可以很容易实现这个任务.记住:闭包是一个内部函数,它可以访问一个或者多个外部函数的外部局部变量.每次闭包的成功调用后这些外部局部变量都保存他们的值(状态).当然如果要创建一个闭包必须要创建其外部局部变量.所以一个典型的闭包的结构包含

python学习笔记七:条件&循环语句

1.print/import更多信息 print打印多个表达式,使用逗号隔开 >>> print 'Age:',42 Age: 42   #注意个结果之间有一个空格符 import:从模块导入函数 import 模块 from 模块 import 函数 from 模块 import * 如果两个模块都有open函数的时候, 1)使用下面方法使用: module1.open()... module2.open()... 2)语句末尾增加as子句 >>> import ma

opencv学习笔记(四)投影

opencv学习笔记(四)投影 任选了一张图片用于测试,图片如下所示: 1 #include <cv.h> 2 #include <highgui.h> 3 using namespace std; 4 using namespace cv; 5 int main() 6 { 7 IplImage * src = cvLoadImage("cat.png", 0); //强制转化读取图像为灰度图 8 cvShowImage("灰度图像", s

swift学习笔记(七)自动引用计数

与Object-c一样,swift使用自动引用计数来跟踪并管理应用使用的内存.当实例不再被使用时,及retainCount=0时,会自动释放是理所占用的内存空间. 注:引用计数仅适用于类的实例,因为struct和enumeration属于值类型,也就不牵涉引用,所以其存储和管理方式并不是引用计数. 当一个实例被初始化时,系统会自动分配一定的内存空间,用于管理属性和方法.当实例对象不再被使用时,其内存空间被收回. swift中的引用类型分为三种,即Strong强引用,weak弱引用和无主引用unw

OpenCV学习笔记(01)我的第一个OpenCV程序(环境配置)

昨天刚刚考完编译原理,私心想着可以做一些与考试无关的东西了.一直想做和图像处理相关的东西,趁这段时间有空学习一下OpenCV,搭建环境真是一件麻烦的事情,搞了近三个小时终于OK了.先来张图: 大致描述一下步骤吧: 一.安装前准备 1.VS2012(网上看到很多用的VS2010,但是基本不影响) 2.OpenCV 安装包(我下载的是最新的2.4.9) 二.安装OpenCV 1.解压OPenCV 说是安装,其实就是解压,OpenCV的Windows安装程序就是一个自解压程序: 这里我解压到C:\Pr