机器学习之用Hog+Svm人脸检测、交通标志和字符识别等(初学者)
2018-03-06 23:34
267 查看
首先声明,这里主要用svm进行一个简单的二分类,最后得到结果,我们把正样本设为1,负样本设为0。
这里只是一个简单的介绍,后面会有相关详细介绍的链接,个人认为比较好的,对我们比较有帮助的链接,有兴趣的可以去看看。当然,本文对初学者有点帮助,也特别欢迎大神来拍!
训练样本时候问题:
我在训练的时候,用了各种样本,总结了一点自己的经验。如果要是用Haar特征训练时,正负样本大概比至少为1:10时候才比较好。而svm训练,更讲究正负样本的选择。其实,机器学习也好,深入学习也好,样本比算法重要的多!(当然,你要是想仔细研究算法内部并且自己写的除外)。我们这里先只是用opencv里的自带的svm和hog库。
先说正负样本的选择。
对于正负样本来说,尽可能的接近比随便挑的效果要好太多。比如说,我们负样本的选择是从几张图片随机抠出几万张负样本出来(过程很简单,用opencv十几二十几行代码就可以,需要的可以评论,我发给你)。然后正样本是我们需要的图片。这时候,我们进行训练完毕后,在做检测,会发现结果相当不好,可以这么说,除非你的检测图片正好是你的正样本训练图片。否则基本检测不出来!!
后来改变了选择,正样本不要只要需求的那一部分,比如,我们检测交通标志时,把交通标志的旁边一圈也划进来,当然不要太多。然后,我们把负样本和正样本的选择尽可能相近,比如,我们训练交通标志时,选择限速50为正样本,那么,我们就把限速40作为负样本,这样,最后得到的效果就会非常好。
对于样本大小的选择上,根据不同的样本取不同大小吧,很多人在这点都没有提到,其实,对于初学者来说,往往不会选择样本大小,特别是还没怎么看svm和hog的,对于样本大小往往是朝网上copy。我们选择样本大小时,一般,人脸,交通检测这些,设置为64*64的就可以。而行人的,一般选择长方形,即64*128这种的。正负样本尽可能保持大小相同。
至于如何取得文件夹下所有的图片目录,和如何每隔一行加一个标志符号。这里,可以自己写一个代码,当然,也可以直接利用.bat直接写,具体方法是:
首先,拿正样本
4000
为例。
在你放置正样本的文件夹下,即与图片的是同一级的目录,新建一个.txt,名字可以自己取,例如为test.txt。然后,修改后缀名,为.bat。右键编辑(对于没有编辑的win10来说…可以下载一个文本编辑器,我用的是EditPlus)打开,然后,在里面输入
@echo off & setlocal EnableDelayedExpansion
for /f “delims=” %%i in (‘“dir /a/s/b/on .“’) do (
set file=%%~fi
set file=!file:/=/!
echo !file! >> 路径.txt
)
点击保存,然后,直接双击这个文件,就会得到一个名为路径.txt,这里面存放的就是文件夹下所有的路径。
PS:至于有的人说的用cmd写一个,dir /b/s/p/w *.jpg>train_list.txt,应该也可以,不过这个有个问题是如果路径太多,不会全部写进去,所以,还是用上一种方法比较好。
然后,打开路径,Ctrl+A,全部复制,然后放到word里,在word里,Ctrl+h,把jpg换为jpg^p1,其中^p是回车符号,1表示正样本。
同理对负样本这样处理,然后,把所有目录统一拷贝到一个.txt里,放到需要的目录下。
然后,我用的opencv是2.4.9版本。
说明:这是在别人的代码上(后面有链接),感觉不错,改了一下,自己拿来用下。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
然后是进行检测的代码,我们平时写的时候,也建议把这两个分开来写,可以写成两个工程,或者用MFC写成两个不同的模块都可以的。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
说明一下,这会在”F:\MLHogSvm\SVM_PREDICT.txt” 里进行说明,如果检测出来的测试图片为需要的,就是标记为1,如果是无关的图片,就会被标记为0(这里随意取,也可以自己设置为其他数,不过要记住的,在后面的检测会用到)。
其实,我们从这段代码也可以看出,用hog和svm检测,最后得出的,只是一个分类结果,就是,可以把一张图片,分成是否是正样本还是负样本的类型。如果是需要的,就分到正样本里(当然,这是完全理想状态下)。
然后,进行检测时,还是需要再次处理,比如,一幅图片,如何才能得到我们想要的大体正样本的框的地方。
参考了N篇论文之后,之后得到一个结果…硕士论文不靠谱。。不是,是大体都一样,简单来讲,如果你真的需要一个实时在线检测的,即使你用了多线程GPU加速之类的,还是达不到要求。说明算法真的是有问题。
最后总结来说,如果是离线检测,那么,RGB转HSI,再进行边缘检测,颜色填充,再边缘检测,再进行模式匹配的效果比较好。
如果你要求速率很高,推荐一种颜色空间,叫做SVF向量颜色空间,最后得到的效果不错,当然,也可以用基于RGB的,不过效果一般。其实,最后要是想要快速结果,GPU加速应该是必不可少的,否则,用个HOG检测就用了8、9秒,还玩个锤子!在线检测,一般用SVF或者基于HSI的吧,就正负样本多采集一点才好。
好了,最后总结说,正负样本多多益善,尽可能相近。对于机器学习来讲,采集样本往往重要的多,如果你按照代码测试过后,还是发现得不到想要的结果。那基本可以断定,你所取得样本是有问题的。所以,弄好样本!才是机器学习的重中之重!!!
链接:http://blog.csdn.net/qianqing13579/article/details/46509037
http://blog.csdn.net/v_july_v/article/details/7624837
这里只是一个简单的介绍,后面会有相关详细介绍的链接,个人认为比较好的,对我们比较有帮助的链接,有兴趣的可以去看看。当然,本文对初学者有点帮助,也特别欢迎大神来拍!
训练样本时候问题:
我在训练的时候,用了各种样本,总结了一点自己的经验。如果要是用Haar特征训练时,正负样本大概比至少为1:10时候才比较好。而svm训练,更讲究正负样本的选择。其实,机器学习也好,深入学习也好,样本比算法重要的多!(当然,你要是想仔细研究算法内部并且自己写的除外)。我们这里先只是用opencv里的自带的svm和hog库。
先说正负样本的选择。
对于正负样本来说,尽可能的接近比随便挑的效果要好太多。比如说,我们负样本的选择是从几张图片随机抠出几万张负样本出来(过程很简单,用opencv十几二十几行代码就可以,需要的可以评论,我发给你)。然后正样本是我们需要的图片。这时候,我们进行训练完毕后,在做检测,会发现结果相当不好,可以这么说,除非你的检测图片正好是你的正样本训练图片。否则基本检测不出来!!
后来改变了选择,正样本不要只要需求的那一部分,比如,我们检测交通标志时,把交通标志的旁边一圈也划进来,当然不要太多。然后,我们把负样本和正样本的选择尽可能相近,比如,我们训练交通标志时,选择限速50为正样本,那么,我们就把限速40作为负样本,这样,最后得到的效果就会非常好。
对于样本大小的选择上,根据不同的样本取不同大小吧,很多人在这点都没有提到,其实,对于初学者来说,往往不会选择样本大小,特别是还没怎么看svm和hog的,对于样本大小往往是朝网上copy。我们选择样本大小时,一般,人脸,交通检测这些,设置为64*64的就可以。而行人的,一般选择长方形,即64*128这种的。正负样本尽可能保持大小相同。
至于如何取得文件夹下所有的图片目录,和如何每隔一行加一个标志符号。这里,可以自己写一个代码,当然,也可以直接利用.bat直接写,具体方法是:
首先,拿正样本
4000
为例。
在你放置正样本的文件夹下,即与图片的是同一级的目录,新建一个.txt,名字可以自己取,例如为test.txt。然后,修改后缀名,为.bat。右键编辑(对于没有编辑的win10来说…可以下载一个文本编辑器,我用的是EditPlus)打开,然后,在里面输入
@echo off & setlocal EnableDelayedExpansion
for /f “delims=” %%i in (‘“dir /a/s/b/on .“’) do (
set file=%%~fi
set file=!file:/=/!
echo !file! >> 路径.txt
)
点击保存,然后,直接双击这个文件,就会得到一个名为路径.txt,这里面存放的就是文件夹下所有的路径。
PS:至于有的人说的用cmd写一个,dir /b/s/p/w *.jpg>train_list.txt,应该也可以,不过这个有个问题是如果路径太多,不会全部写进去,所以,还是用上一种方法比较好。
然后,打开路径,Ctrl+A,全部复制,然后放到word里,在word里,Ctrl+h,把jpg换为jpg^p1,其中^p是回车符号,1表示正样本。
同理对负样本这样处理,然后,把所有目录统一拷贝到一个.txt里,放到需要的目录下。
然后,我用的opencv是2.4.9版本。
说明:这是在别人的代码上(后面有链接),感觉不错,改了一下,自己拿来用下。
#include "stdafx.h" #include "cv.h" #include "highgui.h" #include "stdafx.h" #include <ml.h> #include <iostream> #include <fstream> #include <string> #include <vector> using namespace cv; using namespace std; /************************************************************** 说明:把所有的训练样本(包括正样本和负样本)信息,储存到 F:\\MLHogSvm\\TrainData.txt中,格式为: 上面是:图片路径,其下面为标志,1为正样本,0为负样本 每隔一行做一次,最后放到上面的txt中 最后的.xml放到F:\\MLHogSvm目录下 **************************************************************/ int _tmain(int argc, _TCHAR* argv[]) { int ImgWidht = 64; int ImgHeight = 64;//训练图像大小,可以自己在这里调节,不过最后要看看 vector<string> img_path;//输入文件名变量 vector<int> img_catg; int nLine = 0; string buf; ifstream svm_data( "F:\\MLHogSvm\\TrainData.txt" );//首先,这里搞一个文件列表,把训练样本图片的路径都写在这个txt文件中,使用bat批处理文件可以得到这个txt文件 unsigned long n; while( svm_data )//将训练样本文件依次读取进来 { if( getline( svm_data, buf ) ) { nLine ++; if( nLine % 2 == 0 )//这里的分类比较有意思,看得出来上面的SVM_DATA.txt文本中应该是一行是文件路径,接着下一行就是该图片的类别,可以设置为0或者1,当然多个也无所谓 { img_catg.push_back( atoi( buf.c_str() ) );//atoi将字符串转换成整型,标志(0,1),注意这里至少要有两个类别,否则会出错 } else { img_path.push_back( buf );//图像路径 } } } svm_data.close();//关闭文件 CvMat *data_mat, *res_mat; int nImgNum = nLine / 2; //读入样本数量 ,因为是每隔一行才是图片路径,所以要除以2 ////样本矩阵,nImgNum:横坐标是样本数量, WIDTH * HEIGHT:样本特征向量,即图像大小 data_mat = cvCreateMat( nImgNum, 3780, CV_32FC1 ); //这里第二个参数,即矩阵的列是由下面的descriptors的大小决定的,可以由descriptors.size()得到,且对于不同大小的输入训练图片,这个值是不同的 cvSetZero( data_mat ); //类型矩阵,存储每个样本的类型标志 res_mat = cvCreateMat( nImgNum, 1, CV_32FC1 ); cvSetZero( res_mat ); IplImage* src; IplImage* trainImg=cvCreateImage(cvSize(ImgWidht,ImgHeight),8,3);//需要分析的图片,这里默认设定图片是64*64大小,所以上面定义了1764,如果要更改图片大小,可以先用debug查看一下descriptors是多少,然后设定好再运行 //开始搞HOG特征 for( string::size_type i = 0; i != img_path.size(); i++ ) { src=cvLoadImage(img_path[i].c_str(),1); if( src == NULL ) { cout<<" can not load the image: "<<img_path[i].c_str()<<endl; continue; } cout<<" processing "<<img_path[i].c_str()<<endl; cvResize(src,trainImg); //读取图片 HOGDescriptor *hog=new HOGDescriptor(cvSize(ImgWidht,ImgHeight),cvSize(16,16),cvSize(8,8),cvSize(8,8),9); //具体意思见参考文章1,2 vector<float>descriptors;//结果数组 hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //调用计算函数开始计算 cout<<"HOG dims: "<<descriptors.size()<<endl; //CvMat* SVMtrainMat=cvCreateMat(descriptors.size(),1,CV_32FC1); n=0; for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++) { cvmSet(data_mat,i,n,*iter);//把HOG存储下来 n++; } //cout<<SVMtrainMat->rows<<endl; cvmSet( res_mat, i, 0, img_catg[i] ); cout<<" end processing "<<img_path[i].c_str()<<" "<<img_catg[i]<<endl; } CvSVM svm;//新建一个SVM CvSVMParams param;//这里是参数 CvTermCriteria criteria; criteria = cvTermCriteria( CV_TERMCRIT_EPS, 1000, FLT_EPSILON ); param = CvSVMParams( CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.09, 1.0, 10.0, 0.5, 1.0, NULL, criteria ); /* SVM种类:CvSVM::C_SVC Kernel的种类:CvSVM::RBF degree:10.0(此次不使用) gamma:8.0 coef0:1.0(此次不使用) C:10.0 nu:0.5(此次不使用) p:0.1(此次不使用) 然后对训练数据正规化处理,并放在CvMat型的数组里。 */ //☆☆☆☆☆☆☆☆☆(5)SVM学习☆☆☆☆☆☆☆☆☆☆☆☆ svm.train( data_mat, res_mat, NULL, NULL, param );//训练啦 //☆☆利用训练数据和确定的学习参数,进行SVM学习☆☆☆☆ svm.save( "F:\\MLHogSvm\\SVM_DATA.xml" ); cvReleaseMat( &data_mat ); cvReleaseMat( &res_mat ); return 0; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
然后是进行检测的代码,我们平时写的时候,也建议把这两个分开来写,可以写成两个工程,或者用MFC写成两个不同的模块都可以的。
#include "stdafx.h" #include "cv.h" #include "highgui.h" #include "stdafx.h" #include <ml.h> #include <iostream> #include <fstream> #include <string> #include <vector> using namespace cv; using namespace std; /********************************************************************* 说明: 读取svm.load("F:\\MLHogSvm\\SVM_DATA.xml"),读入原来写入的.xml 先F:\\MLHogSvm\\TrainTest.txt中,存放的是要进行测试的图片的信息。 预测结果(1为正样本,0为负样本)放入"F:\\MLHogSvm\\SVM_PREDICT.txt" 中 **********************************************************************/ int _tmain(int argc, _TCHAR* argv[]) { int ImgWidht = 64; int ImgHeight = 64;//训练图像大小,可以自己在这里调节,不过最后要看看 IplImage *test; vector<string> img_tst_path; ifstream img_tst( "F:\\MLHogSvm\\TrainTest.txt" );//输入测试图片路径信息 string buf; while( img_tst ) { if( getline( img_tst, buf ) ) { img_tst_path.push_back( buf ); } } img_tst.close(); CvMat *test_hog = cvCreateMat( 1, 3780, CV_32FC1 );//注意这里的1764,同上面一样 char line[512]; ofstream predict_txt( "F:\\MLHogSvm\\SVM_PREDICT.txt" );//把预测结果存储在这个文本中 for( string::size_type j = 0; j != img_tst_path.size(); j++ )//依次遍历所有的待检测图片 { test = cvLoadImage( img_tst_path[j].c_str(), 1); if( test == NULL ) { cout<<" can not load the image: "<<img_tst_path[j].c_str()<<endl; continue; } IplImage* trainImg=cvCreateImage(cvSize(ImgWidht,ImgHeight),8,3); cvZero(trainImg); cvResize(test,trainImg); //读取图片 HOGDescriptor *hog=new HOGDescriptor(cvSize(ImgWidht,ImgHeight),cvSize(16,16),cvSize(8,8),cvSize(8,8),9); vector<float>descriptors;//结果数组 hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //调用计算函数开始计算 cout<<"HOG dims: "<<descriptors.size()<<endl; CvMat* SVMtrainMat=cvCreateMat(1,descriptors.size(),CV_32FC1); unsigned long n=0; for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++) { cvmSet(SVMtrainMat,0,n,*iter); n++; } CvSVM svm;//新建一个SVM svm.load("F:\\MLHogSvm\\SVM_DATA.xml"); int ret = svm.predict(SVMtrainMat);//获取最终检测结果,这个predict的用法见 OpenCV的文档 std::sprintf( line, "%s %d\r\n", img_tst_path[j].c_str(), ret ); predict_txt<<line; } predict_txt.close(); return 0; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
说明一下,这会在”F:\MLHogSvm\SVM_PREDICT.txt” 里进行说明,如果检测出来的测试图片为需要的,就是标记为1,如果是无关的图片,就会被标记为0(这里随意取,也可以自己设置为其他数,不过要记住的,在后面的检测会用到)。
其实,我们从这段代码也可以看出,用hog和svm检测,最后得出的,只是一个分类结果,就是,可以把一张图片,分成是否是正样本还是负样本的类型。如果是需要的,就分到正样本里(当然,这是完全理想状态下)。
然后,进行检测时,还是需要再次处理,比如,一幅图片,如何才能得到我们想要的大体正样本的框的地方。
参考了N篇论文之后,之后得到一个结果…硕士论文不靠谱。。不是,是大体都一样,简单来讲,如果你真的需要一个实时在线检测的,即使你用了多线程GPU加速之类的,还是达不到要求。说明算法真的是有问题。
最后总结来说,如果是离线检测,那么,RGB转HSI,再进行边缘检测,颜色填充,再边缘检测,再进行模式匹配的效果比较好。
如果你要求速率很高,推荐一种颜色空间,叫做SVF向量颜色空间,最后得到的效果不错,当然,也可以用基于RGB的,不过效果一般。其实,最后要是想要快速结果,GPU加速应该是必不可少的,否则,用个HOG检测就用了8、9秒,还玩个锤子!在线检测,一般用SVF或者基于HSI的吧,就正负样本多采集一点才好。
好了,最后总结说,正负样本多多益善,尽可能相近。对于机器学习来讲,采集样本往往重要的多,如果你按照代码测试过后,还是发现得不到想要的结果。那基本可以断定,你所取得样本是有问题的。所以,弄好样本!才是机器学习的重中之重!!!
链接:http://blog.csdn.net/qianqing13579/article/details/46509037
http://blog.csdn.net/v_july_v/article/details/7624837
相关文章推荐
- 机器学习之用Hog+Svm人脸检测、交通标志和字符识别等(初学者)
- opencv开发笔记(十六):人脸检测的方法——HOG+SVM,类“CascadeClassifier”
- 机器学习实验(九):基于高斯分布和OneClassSVM的异常点检测
- 程序员的机器学习入门笔记(九):人脸检测之Haar分类器方法:Haar特征、积分图、 AdaBoost 、级联
- SVM人脸样本训练检测流程
- 人脸识别SVM算法实现--参考麦子学院彭亮机器学习基础5.2
- 简单实现一个人脸检测器(HOG+SVM实现人脸检测)
- 机器学习-人脸检测和Haar分类器
- 机器学习: Viola-Jones 人脸检测算法解析(一)
- 简单实现一个人脸检测器(HOG+SVM实现人脸检测)
- 机器学习 以及人脸检测 相关资料
- 使用OpenCV+PCA+KNN/SVM进行人脸检测和识别-Python
- 机器学习: Viola-Jones 人脸检测算法解析(二)
- opencv机器学习 Haar特征 LBP特征 adaboost集成学习 级联分类器 支持向量机SVM 主成分分析PCA 人工神经网络(ANN) 笑脸检测 SVM分类 笑脸 检测
- 机器学习人脸检测和识别(中文标记姓名) python+opencv+freetype 图文教程和项目源代码
- PCA应用---检测人脸的简单示例 (MATLAB版)
- 人脸检测和识别及python实现系列(1)-- 环境配置和相关类库安装
- 人脸识别之人脸检测(九)--检测器源码分析
- 人脸Pose检测:ASM、AAM、CLM总结
- 机器学习(二)--- SVM学习:理论基础理解