当前位置: 首页 > news >正文

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中,每一行的最后一个数字代表该行路径下的图片的识别结果。如下图所示:

  

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

  

  

  

  

转载于:https://www.cnblogs.com/codingmengmeng/p/5613442.html

相关文章:

  • ffmpeg mp4转yuv
  • BZOJ1237: [SCOI2008]配对
  • NGUI 指定视口大小
  • SHELL--待续
  • 意志力和自律
  • 实验二、作业调度模拟程序
  • mysql select不使用任何锁(select with nolock)
  • Day5 双层装饰器、字符串格式化、生成器、迭代器、递归
  • Linux内核里的DebugFS
  • Linux 必掌握的 SQL 命令
  • curl的使用(from 阮一峰)
  • 对接微信红包时:CA证书出错,请登录微信支付商户平台下载证书
  • 深入理解JAVA I/O系列一:File
  • Java中的一些方法
  • Ubuntu server 16.04 安装mysql并设置远程访问
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • 4. 路由到控制器 - Laravel从零开始教程
  • 78. Subsets
  • Computed property XXX was assigned to but it has no setter
  • css布局,左右固定中间自适应实现
  • docker容器内的网络抓包
  • Java 多线程编程之:notify 和 wait 用法
  • js中的正则表达式入门
  • k个最大的数及变种小结
  • leetcode讲解--894. All Possible Full Binary Trees
  • Nacos系列:Nacos的Java SDK使用
  • Python打包系统简单入门
  • Rancher-k8s加速安装文档
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 和 || 运算
  • 简单易用的leetcode开发测试工具(npm)
  • 前端技术周刊 2019-01-14:客户端存储
  • 入口文件开始,分析Vue源码实现
  • 学习笔记TF060:图像语音结合,看图说话
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • Mac 上flink的安装与启动
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • #在 README.md 中生成项目目录结构
  • (33)STM32——485实验笔记
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (pytorch进阶之路)扩散概率模型
  • (二)linux使用docker容器运行mysql
  • (二)PySpark3:SparkSQL编程
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (离散数学)逻辑连接词
  • (十一)手动添加用户和文件的特殊权限
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (一)Linux+Windows下安装ffmpeg
  • (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版
  • .Net core 6.0 升8.0
  • .Net Core 中间件验签
  • .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
  • @javax.ws.rs Webservice注解