HOG+SVM行人检测的两种方法
来源:互联网 发布:楚天手动编程g代码结尾 编辑:程序博客网 时间:2024/05/20 18:17
HOG+SVM行人检测的两种方法
轉載http://blog.csdn.net/qianqing13579/article/details/46509037
关于HOG+SVM,CSDN上有一些非常好的文章,这里给出我觉得写的比较好的几篇,仅供大家参考
目标检测的图像特征提取之(一)HOG特征
HOG:从理论到OpenCV实践
opencv 学习笔记-入门(21)之三线性插值-hog(二)
这篇博客写的是关于三线性插值的,为了减少混叠效应的,写的很好OpenCV中的HOG+SVM物体分类
OpenCV HOGDescriptor 参数图解
利用Hog特征和SVM分类器进行行人检测
以上就是个人觉得写的比较好的博客,基本上将上面的博客看懂了,HOG也比较理解了,如果还想输入了解HOG,建议直接看OpenCV HOG的源码
下面,就说说使用OpenCV 中的HOG+SVM实现行人检测的两种方式
说明:程序运行环境为VS2013+OpenCV3.0
第一种
先说第一种方式,直接上代码:
///////////////////////////////////HOG+SVM识别方式2/////////////////////////////////////////////////// void Train(){ ////////////////////////////////读入训练样本图片路径和类别/////////////////////////////////////////////////// //图像路径和类别 vector<string> imagePath; vector<int> imageClass; int numberOfLine = 0; string buffer; ifstream trainingData(string(FILEPATH)+"TrainData.txt"); unsigned long n; while (!trainingData.eof()) { getline(trainingData, buffer); if (!buffer.empty()) { ++numberOfLine; if (numberOfLine % 2 == 0) { //读取样本类别 imageClass.push_back(atoi(buffer.c_str())); } else { //读取图像路径 imagePath.push_back(buffer); } } } //关闭文件 trainingData.close(); ////////////////////////////////获取样本的HOG特征/////////////////////////////////////////////////// //样本特征向量矩阵 int numberOfSample = numberOfLine / 2; Mat featureVectorOfSample(numberOfSample, 3780, CV_32FC1);//矩阵中每行为一个样本 //样本的类别 Mat classOfSample(numberOfSample, 1, CV_32SC1); Mat convertedImage; Mat trainImage; // 计算HOG特征 for (vector<string>::size_type i = 0; i <= imagePath.size() - 1; ++i) { //读入图片 Mat src = imread(imagePath[i], -1); if (src.empty()) { cout << "can not load the image:" << imagePath[i] << endl; continue; } //cout << "processing:" << imagePath[i] << endl; // 归一化 resize(src, trainImage, Size(64, 128)); // 提取HOG特征 HOGDescriptor hog(cvSize(64, 128), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9); vector<float> descriptors; double time1 = getTickCount(); hog.compute(trainImage, descriptors);//这里可以设置检测窗口步长,如果图片大小超过64×128,可以设置winStride double time2 = getTickCount(); double elapse_ms = (time2 - time1) * 1000 / getTickFrequency(); //cout << "HOG dimensions:" << descriptors.size() << endl; //cout << "Compute time:" << elapse_ms << endl; //保存到特征向量矩阵中 for (vector<float>::size_type j = 0; j <= descriptors.size() - 1; ++j) { featureVectorOfSample.at<float>(i, j) = descriptors[j]; } //保存类别到类别矩阵 //!!注意类别类型一定要是int 类型的 classOfSample.at<int>(i, 0) = imageClass[i]; } ///////////////////////////////////使用SVM分类器训练/////////////////////////////////////////////////// //设置参数,注意Ptr的使用 Ptr<SVM> svm = SVM::create(); svm->setType(SVM::C_SVC); svm->setKernel(SVM::LINEAR);//注意必须使用线性SVM进行训练,因为HogDescriptor检测函数只支持线性检测!!! svm->setTermCriteria(TermCriteria(CV_TERMCRIT_ITER, 1000, FLT_EPSILON)); //使用SVM学习 svm->train(featureVectorOfSample, ROW_SAMPLE, classOfSample); //保存分类器(里面包括了SVM的参数,支持向量,α和rho) svm->save(string(FILEPATH) + "Classifier.xml"); /* SVM训练完成后得到的XML文件里面,有一个数组,叫做support vector,还有一个数组,叫做alpha,有一个浮点数,叫做rho; 将alpha矩阵同support vector相乘,注意,alpha*supportVector,将得到一个行向量,将该向量前面乘以-1。之后,再该行向量的最后添加一个元素rho。 如此,变得到了一个分类器,利用该分类器,直接替换opencv中行人检测默认的那个分类器(cv::HOGDescriptor::setSVMDetector()), */ //获取支持向量机:矩阵默认是CV_32F Mat supportVector = svm->getSupportVectors();// //获取alpha和rho Mat alpha;//每个支持向量对应的参数α(拉格朗日乘子),默认alpha是float64的 Mat svIndex;//支持向量所在的索引 float rho = svm->getDecisionFunction(0, alpha, svIndex); //转换类型:这里一定要注意,需要转换为32的 Mat alpha2; alpha.convertTo(alpha2, CV_32FC1); //结果矩阵,两个矩阵相乘 Mat result(1, 3780, CV_32FC1); result = alpha2*supportVector; //乘以-1,这里为什么会乘以-1? //注意因为svm.predict使用的是alpha*sv*another-rho,如果为负的话则认为是正样本,在HOG的检测函数中,使用rho+alpha*sv*another(another为-1) for (int i = 0; i < 3780; ++i) result.at<float>(0, i) *= -1; //将分类器保存到文件,便于HOG识别 //这个才是真正的判别函数的参数(ω),HOG可以直接使用该参数进行识别 FILE *fp = fopen((string(FILEPATH) + "HOG_SVM.txt").c_str(), "wb"); for (int i = 0; i<3780; i++) { fprintf(fp, "%f \n", result.at<float>(0,i)); } fprintf(fp, "%f", rho); fclose(fp);}// 使用训练好的分类器识别void Detect(){ Mat img; FILE* f = 0; char _filename[1024]; // 获取测试图片文件路径 f = fopen((string(FILEPATH) + "TestData.txt").c_str(), "rt"); if (!f) { fprintf(stderr, "ERROR: the specified file could not be loaded\n"); return; } //加载训练好的判别函数的参数(注意,与svm->save保存的分类器不同) vector<float> detector; ifstream fileIn(string(FILEPATH) + "HOG_SVM.txt", ios::in); float val = 0.0f; while (!fileIn.eof()) { fileIn >> val; detector.push_back(val); } fileIn.close(); //设置HOG HOGDescriptor hog; hog.setSVMDetector(detector);// 使用自己训练的分类器 //hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());//可以直接使用05 CVPR已训练好的分类器,这样就不用Train()这个步骤了 namedWindow("people detector", 1); // 检测图片 for (;;) { // 读取文件名 char* filename = _filename; if (f) { if (!fgets(filename, (int)sizeof(_filename)-2, f)) break; //while(*filename && isspace(*filename)) // ++filename; if (filename[0] == '#') continue; //去掉空格 int l = (int)strlen(filename); while (l > 0 && isspace(filename[l - 1])) --l; filename[l] = '\0'; img = imread(filename); } printf("%s:\n", filename); if (!img.data) continue; fflush(stdout); vector<Rect> found, found_filtered; double t = (double)getTickCount(); // run the detector with default parameters. to get a higher hit-rate // (and more false alarms, respectively), decrease the hitThreshold and // groupThreshold (set groupThreshold to 0 to turn off the grouping completely). //多尺度检测 hog.detectMultiScale(img, found, 0, Size(8, 8), Size(32, 32), 1.05, 2); t = (double)getTickCount() - t; printf("detection time = %gms\n", t*1000. / cv::getTickFrequency()); size_t i, j; //去掉空间中具有内外包含关系的区域,保留大的 for (i = 0; i < found.size(); i++) { Rect r = found[i]; for (j = 0; j < found.size(); j++) if (j != i && (r & found[j]) == r) break; if (j == found.size()) found_filtered.push_back(r); } // 适当缩小矩形 for (i = 0; i < found_filtered.size(); i++) { Rect r = found_filtered[i]; // the HOG detector returns slightly larger rectangles than the real objects. // so we slightly shrink the rectangles to get a nicer output. r.x += cvRound(r.width*0.1); r.width = cvRound(r.width*0.8); r.y += cvRound(r.height*0.07); r.height = cvRound(r.height*0.8); rectangle(img, r.tl(), r.br(), cv::Scalar(0, 255, 0), 3); } imshow("people detector", img); int c = waitKey(0) & 255; if (c == 'q' || c == 'Q' || !f) break; } if (f) fclose(f); return;}void HOG_SVM2(){ //如果使用05 CVPR提供的默认分类器,则不需要Train(),直接使用Detect检测图片 Train(); Detect();}int main(){ //HOG+SVM识别方式1:直接输出类别 //HOG_SVM1(); //HOG+SVM识别方式2:输出图片中的存在目标的矩形 HOG_SVM2();}
- 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
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
这里我想说明一下TrainData.txt,这个文件放置了所有样本的路径和类别,如下:
关
于如何读取正负样本的路径到txt文件,可以使用批处理文件,批处理文件我上传到了CSDN,大家可以去下载
点击下载
正负样本至少保证有1000,不能太少,否则效果就不好了,其中HOG_SVM.txt里面包含了判别函数的参数,这个参数可以直接给HOG用
下面就是我的测试效果:
检测效果还可以.
测试图片我也上传到网上了
点击下载
当然你也可以不用自己训练分类器,直接使用OpenCV自带的分类器,OpenCV自带的分类器使用的是05年CVPR那篇文章中作者训练好的分类器,下面我们就来看看效果:
图中可以看出,OpenCV自带的分类器效果要比自己训练的好,主要原因大概有以下几点
1.训练样本不足,我的正负样本才900多
2.正样本图片不够清晰,导致特征提取有比较大的误差
最近有人在运行博客中程序的时候出现了问题,让我看看程序,我也不太清楚什么问题,所以我将整个程序和程序测试数据打包了一下,上传到了CSDN上。
点击下载
解压后,将”Pedestrians64x128”文件夹放置在D盘根目录,然后使用HOG.cpp新建一个工程,直接可以运行。
注:环境是VS2013+OpenCV3.0.0,Release版本
第二种
下面说说第二种方式,第二种方式就是传统的方式了,就是对于测试样本,提取特征,然后使用训练好的分类器进行识别,代码
///////////////////////////////////HOG+SVM识别方式1///////////////////////////////////////////////////void HOG_SVM1(){ ////////////////////////////////读入训练样本图片路径和类别/////////////////////////////////////////////////// //图像路径和类别 vector<string> imagePath; vector<int> imageClass; int numberOfLine = 0; string buffer; ifstream trainingData(string(FILEPATH) + "TrainData.txt", ios::in); unsigned long n; while (!trainingData.eof()) { getline(trainingData, buffer); if (!buffer.empty()) { ++numberOfLine; if (numberOfLine % 2 == 0) { //读取样本类别 imageClass.push_back(atoi(buffer.c_str())); } else { //读取图像路径 imagePath.push_back(buffer); } } } trainingData.close(); ////////////////////////////////获取样本的HOG特征/////////////////////////////////////////////////// //样本特征向量矩阵 int numberOfSample = numberOfLine / 2; Mat featureVectorOfSample(numberOfSample, 3780, CV_32FC1);//矩阵中每行为一个样本 //样本的类别 Mat classOfSample(numberOfSample, 1, CV_32SC1); //开始计算训练样本的HOG特征 for (vector<string>::size_type i = 0; i <= imagePath.size() - 1; ++i) { //读入图片 Mat src = imread(imagePath[i], -1); if (src.empty()) { cout << "can not load the image:" << imagePath[i] << endl; continue; } cout << "processing" << imagePath[i] << endl; //缩放 Mat trainImage; resize(src, trainImage, Size(64, 128)); //提取HOG特征 HOGDescriptor hog(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9); vector<float> descriptors; hog.compute(trainImage, descriptors);//这里可以设置检测窗口步长,如果图片大小超过64×128,可以设置winStride cout << "HOG dimensions:" << descriptors.size() << endl; //保存特征向量矩阵中 for (vector<float>::size_type j = 0; j <= descriptors.size() - 1; ++j) { featureVectorOfSample.at<float>(i, j) = descriptors[j]; } //保存类别到类别矩阵 //!!注意类别类型一定要是int 类型的 classOfSample.at<int>(i, 0) = imageClass[i]; } ///////////////////////////////////使用SVM分类器训练/////////////////////////////////////////////////// //设置参数 //参考3.0的Demo Ptr<SVM> svm = SVM::create(); svm->setKernel(SVM::RBF); svm->setType(SVM::C_SVC); svm->setC(10); svm->setCoef0(1.0); svm->setP(1.0); svm->setNu(0.5); svm->setTermCriteria(TermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON)); //使用SVM学习 svm->train(featureVectorOfSample, ROW_SAMPLE, classOfSample); //保存分类器 svm->save("Classifier.xml"); ///////////////////////////////////使用训练好的分类器进行识别/////////////////////////////////////////////////// vector<string> testImagePath; ifstream testData(string(FILEPATH) + "TestData.txt", ios::out); while (!testData.eof()) { getline(testData, buffer); //读取 if (!buffer.empty()) testImagePath.push_back(buffer); } testData.close(); ofstream fileOfPredictResult(string(FILEPATH) + "PredictResult.txt"); //最后识别的结果 for (vector<string>::size_type i = 0; i <= testImagePath.size() - 1; ++i) { //读取测试图片 Mat src = imread(testImagePath[i], -1); if (src.empty()) { cout << "Can not load the image:" << testImagePath[i] << endl; continue; } //缩放 Mat testImage; resize(src, testImage, Size(64, 64)); //测试图片提取HOG特征 HOGDescriptor hog(cvSize(64, 64), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9); vector<float> descriptors; hog.compute(testImage, descriptors); cout << "HOG dimensions:" << descriptors.size() << endl; Mat featureVectorOfTestImage(1, descriptors.size(), CV_32FC1); for (int j = 0; j <= descriptors.size() - 1; ++j) { featureVectorOfTestImage.at<float>(0, j) = descriptors[j]; } //对测试图片进行分类并写入文件 int predictResult = svm->predict(featureVectorOfTestImage); char line[512]; //printf("%s %d\r\n", testImagePath[i].c_str(), predictResult); std::sprintf(line, "%s %d\n", testImagePath[i].c_str(), predictResult); fileOfPredictResult << line; } fileOfPredictResult.close();}int main(){ //HOG+SVM识别方式1:直接输出类别 HOG_SVM1(); //HOG+SVM识别方式2:输出图片中的存在目标的矩形 //HOG_SVM2();}
- HOG+SVM行人检测的两种方法
- HOG+SVM行人检测的两种方法
- HOG+SVM行人检测的两种方法
- Hog+svm行人检测
- Hog+svm行人检测
- 行人检测HOG+SVM
- Hog+svm行人检测
- Hog+svm行人检测
- hog+svm 行人检测
- hog+svm行人检测
- Hog+svm行人检测
- HOG+SVM行人检测
- hog+SVM行人检测
- 自己训练的Hog+Svm 行人检测
- Hog SVM 车辆 行人检测
- HOG+SVM进行行人检测
- SVM分类器训练的HOG行人检测
- 行人检测HOG+SVM比较通俗的介绍
- 有哪些比呱呱更顶呱呱的财经直播间
- Mac下设置Android源代码编译环境
- 主线程,子线程资源冲突,解决方案
- http请求报400错误的原因分析
- Java多线程系列--【基础篇01】- 基本概念
- HOG+SVM行人检测的两种方法
- 软件介绍(apache lighttpd nginx)
- Java学习第二天
- java版支付宝支付
- SpringBoot构建微服务实战 之 Configuration(一)
- HDU 1686 Oulipo(KMP)
- 单例模式
- Android自定义通用适配器
- 后台实现fancytree遍历节点数据