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”删掉。

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

  首先是训练样本:

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

  

  运行结果:

  

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

  其次是测试样本:

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

  运行结果:

  

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

  SVM训练:

 bool ClogoRecognition::svmTrain()
 {
         vector<string> img_path;//图像路径容器
         vector<int> img_catg;//图像类别容器
         ;
         string buf;
         ifstream svm_data(DEFAULT_TRAINSAMPLES_TXT_DECRIBE_PATH);//训练样本图片的路径都写在这个txt文件中,使用bat批处理文件可以得到这个txt文件
         if (!svm_data)
             return FALSE;
         unsigned long n;
         while (svm_data)//将训练样本文件依次读取进来
         {
             if (getline(svm_data, buf))
             {
                 nLine++;
                  == )//注:奇数行是图片全路径,偶数行是标签
                 {
                     img_catg.push_back(atoi(buf.c_str()));//atoi将字符串转换成整型,标志(0,1,2,...,9),注意这里至少要有两个类别,否则会出错
                 }
                 else
                 {
                     img_path.push_back(buf);//图像路径
                 }
             }
         }
         svm_data.close();//关闭文件
         CvMat *data_mat, *res_mat;
         ; //nImgNum是样本数量,只有文本行数的一半,另一半是标签
         data_mat = cvCreateMat(nImgNum, , CV_32FC1);  //第二个参数,即矩阵的列是由下面的descriptors的大小决定的,可以由descriptors.size()得到,且对于不同大小的输入训练图片,这个值是不同的
         cvSetZero(data_mat);
         //类型矩阵,存储每个样本的类型标志
         res_mat = cvCreateMat(nImgNum, , CV_32FC1);
         cvSetZero(res_mat);
         IplImage* src;
         IplImage* trainImg = cvCreateImage(cvSize(, ), , );//需要分析的图片,这里车标的尺寸归一化至40*32,所以上面定义了432,如果要更改图片大小,可以先用debug查看一下descriptors是多少,然后设定好再运行    

         //处理HOG特征
         ; i != img_path.size(); i++)
         {
             src = cvLoadImage(img_path[i].c_str(), );
             if (src == NULL)
             {
                 cout << " can not load the image: " << img_path[i].c_str() << endl;
                 continue;
             }

             cout << " 处理: " << img_path[i].c_str() << endl;

             cvResize(src, trainImg);
             HOGDescriptor *hog = , ), cvSize(, ), cvSize(, ), cvSize(, ), );//图片尺寸:40*32;block尺寸:16*16;cell尺寸:8*8;检测窗口的滑动步长:8*8;一个单元格内统计9个方向的梯度直方图
             vector<float>descriptors;//存放结果
             hog->compute(trainImg, descriptors, Size(, ), Size(, )); //Hog特征计算
             cout << "HOG dims: " << descriptors.size() << endl;
             n = ;
             for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++)
             {
                 cvmSet(data_mat, i, n, *iter);//存储HOG特征
                 n++;
             }
             cvmSet(res_mat, i, , img_catg[i]);
             cout << " 处理完毕: " << img_path[i].c_str() << " " << img_catg[i] << endl;
         }

         //    CvSVM svm = CvSVM();//新建一个SVM
         CvSVM svm;
         CvSVMParams param;//这里是SVM训练相关参数
         CvTermCriteria criteria;
         criteria = cvTermCriteria(CV_TERMCRIT_EPS, , FLT_EPSILON);
         param = CvSVMParams(CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.09, 1.0, 10.0, 0.5, 1.0, NULL, criteria);
 //        param = CvSVMParams(CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.3, 1.0, 5, 0.5, 1.0, NULL, criteria);
         svm.train(data_mat, res_mat, NULL, NULL, param);//训练数据
         //保存训练好的分类器
         svm.save(DEFAULT_SVMMODEL_PATH);
         cvReleaseMat(&data_mat);
         cvReleaseMat(&res_mat);
         cvReleaseImage(&trainImg);
         return TRUE;
 }

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

  SVM测试:

 bool ClogoRecognition::svmTest()
 {
     string buf;
     CvSVM svm;
     svm.load(DEFAULT_SVMMODEL_PATH);//加载训练好的xml文件
     //检测样本
     IplImage *test;
     ];
     vector<string> img_tst_path;
     ifstream img_tst(DEFAULT_TESTSAMPLES_TXT_DECRIBE_PATH);  //加载需要预测的图片集合,这个文本里存放的是图片全路径,不要标签
     if (!img_tst)
         return FALSE;
     while (img_tst)
     {
         if (getline(img_tst, buf))
         {
             img_tst_path.push_back(buf);
         }
     }
     img_tst.close();

     ofstream predict_txt(DEFAULT_TESTSAMPLES_RECOGNITION_RESULT_TXT_DECRIBE_PATH);//把预测结果存储在这个文本中
     ; j != img_tst_path.size(); j++)//依次遍历所有的待检测图片
     {
         test = cvLoadImage(img_tst_path[j].c_str(), );
         if (test == NULL)
         {
             cout << " can not load the image: " << img_tst_path[j].c_str() << endl;
             continue;//结束本次循环
         }
         IplImage* trainTempImg = cvCreateImage(cvSize(, ), , );
         cvZero(trainTempImg);
         cvResize(test, trainTempImg);
         HOGDescriptor *hog = , ), cvSize(, ), cvSize(, ), cvSize(, ), );
         vector<float>descriptors;//结果数组
         hog->compute(trainTempImg, descriptors, Size(, ), Size(, ));
         cout << "HOG dims: " << descriptors.size() << endl;
         CvMat* SVMtrainMat = cvCreateMat(, descriptors.size(), CV_32FC1);
         ;
         for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++)
         {
             cvmSet(SVMtrainMat, , n, *iter);
             n++;
         }

         int ret = svm.predict(SVMtrainMat);//检测结果
         sprintf(result, "%s  %d\r\n", img_tst_path[j].c_str(), ret);
         predict_txt << result;  //输出检测结果到文本
     }
     predict_txt.close();
     cvReleaseImage(&test);
     return TRUE;
 }

  

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

  

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

  

  

  

  

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

  1. opencv学习笔记(六)直方图比较图片相似度

    opencv学习笔记(六)直方图比较图片相似度 opencv提供了API来比较图片的相似程度,使我们很简单的就能对2个图片进行比较,这就是直方图的比较,直方图英文是histogram, 原理就是就是将 ...

  2. opencv学习笔记(五)镜像对称

    opencv学习笔记(五)镜像对称 设图像的宽度为width,长度为height.(x,y)为变换后的坐标,(x0,y0)为原图像的坐标. 水平镜像变换: 代码实现: #include <ios ...

  3. opencv学习笔记(四)投影

    opencv学习笔记(四)投影 任选了一张图片用于测试,图片如下所示: #include <cv.h> #include <highgui.h> using namespace ...

  4. opencv学习笔记(三)基本数据类型

    opencv学习笔记(三)基本数据类型 类:DataType 将C++数据类型转换为对应的opencv数据类型 OpenCV原始数据类型的特征模版.OpenCV的原始数据类型包括unsigned ch ...

  5. opencv学习笔记(二)寻找轮廓

    opencv学习笔记(二)寻找轮廓 opencv中使用findContours函数来查找轮廓,这个函数的原型为: void findContours(InputOutputArray image, O ...

  6. opencv学习笔记(一)IplImage, CvMat, Mat 的关系

    opencv学习笔记(一)IplImage, CvMat, Mat 的关系 opencv中常见的与图像操作有关的数据容器有Mat,cvMat和IplImage,这三种类型都可以代表和显示图像,但是,M ...

  7. paper 93:OpenCV学习笔记大集锦

    整理了我所了解的有关OpenCV的学习笔记.原理分析.使用例程等相关的博文.排序不分先后,随机整理的.如果有好的资源,也欢迎介绍和分享. 1:OpenCV学习笔记 作者:CSDN数量:55篇博文网址: ...

  8. (转) OpenCV学习笔记大集锦 与 图像视觉博客资源2之MIT斯坦福CMU

          首页 视界智尚 算法技术 每日技术 来打我呀 注册     OpenCV学习笔记大集锦 整理了我所了解的有关OpenCV的学习笔记.原理分析.使用例程等相关的博文.排序不分先后,随机整理的 ...

  9. (转)Qt Model/View 学习笔记 (七)——Delegate类

    Qt Model/View 学习笔记 (七) Delegate  类 概念 与MVC模式不同,model/view结构没有用于与用户交互的完全独立的组件.一般来讲, view负责把数据展示 给用户,也 ...

随机推荐

  1. BZOJ3670 [Noi2014]动物园

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  2. 关于Java中枚举Enum的深入剖析

    在编程语言中我们,都会接触到枚举类型,通常我们进行有穷的列举来实现一些限定.Java也不例外.Java中的枚举类型为Enum,本文将对枚举进行一些比较深入的剖析. 什么是Enum Enum是自Java ...

  3. Java中的受检异常

    Java中的受检异常 Java提供了三种异常类型,受检异常(checked exception).运行时异常(runtime exception).错误(error).那么这受检异常在实际开发中又有什 ...

  4. 【BZOJ 3083】遥远的国度

    这道题很简单的连剖+分类讨论,但是SDOI Round2要来了,不会手动栈怎么办呢?只好用一下这道题练习一下手动栈了,结果调了一天多QwQ 链剖的第一个dfs用bfs水过就行,但是我自以为是地把倍增写 ...

  5. Aufs与Devicemapper的关系

    Aufs与Devicemapper的应用 Aufs是Docker最初采用的文件系统,由于Aufs未能加入到Linux内核,考虑到兼容性问题,加入了Devicemapper的支持.目前,除少数版本如Ub ...

  6. SpringMVC学习系列(9) 之 实现注解式权限验证

    对大部分系统来说都需要权限管理来决定不同用户可以看到哪些内容,那么如何在Spring MVC中实现权限验证呢?当然我们可以继续使用servlet中的过滤器Filter来实现.但借助于Spring MV ...

  7. java基础练习[一]

    moka同学java学习笔记 package moka.hello; public class HelloWorld {     public static void main(String[] ar ...

  8. ytu 1939:统计元音(水题)

    统计元音 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 68  Solved: 33[Submit][Status][Web Board] Descrip ...

  9. SQL语句最基本的性能优化方法

    有些人还不知道sql语句的基本性能优化方法,在此我简单提醒一下,最基本的优化方法:   1.检查是否缺少索引.调试的时候开启“包括实际的执行计划”   执行后会显示缺少的索引,   然后让dba帮助添 ...

  10. ios中get,post和解压缩用法

    一. 网络概念 1. 在Linux系统上,运行的Web服务器的名字叫做Apache 2. 所有的http访问都是基于html或者相关的文件,例如:php,asp,jsp,asp.net 这些文件最终都 ...