,是关于为什么图像的HOG特征向量debug后是15876的问题。答案是因为原作者的窗口是64*64的,所以维数为9*4*7*7=1764(图像的大小也是64*64,所以图像的特征维数与一个窗口的维数是相同的,compute()里的窗口步进(8,8)也是无效的)。而我的图像时64*128大小的,我把窗口也换成
64*128,所以维数就是3780了,与setSVMDetector默认的getDefaultPeopleDetector大小一样(大概小于getDefaultPeopleDetector()大小为(3781*1))的vector传到setSVMDetector()里都没关系吧,不会出现断言错误。
上代码:
1 /*
2 * =====================================================================================
3 *
4 * Filename: people_detector.cpp
5 * Environment:
6 * Description: 行人检测程序,程序里窗口大小和图片大小一样大,都是64*128
7 *
8 *
9 *
10 * Version: 1.0
11 * Created: 2013/10/20 10:45:02
12 * Author: yuliyang
13 I*
14 * Mail: wzyuliyang911@gmail.com
15 * Blog:
16 *
17 * =====================================================================================
18 */
19
20 #include "opencv2/opencv.hpp"
21 #include "windows.h"
22 #include "fstream"
23 #include <iostream>
24 using namespace std;
25 using namespace cv;
26 class Mysvm: public CvSVM
27 {
28 public:
29 int get_alpha_count()
30 {
31 return this->sv_total;
32 }
33
34 int get_sv_dim()
35 {
36 return this->var_all;
37 }
38
39 int get_sv_count()
40 {
41 return this->decision_func->sv_count;
42 }
43
44 double* get_alpha()
45 {
46 return this->decision_func->alpha;
47 }
48
49 float** get_sv()
50 {
51 return this->sv;
52 }
53
54 float get_rho()
55 {
56 return this->decision_func->rho;
57 }
58 };
59
60 int my_train()
61 {
62
63 /*-----------------------------------------------------------------------------
64 * e:/pedestrianDetect-peopleFlow.txt是用来保存所有样本的特征,大小为样本数*3780(每个样本的特征数)
65 *
66 *
67 *
68 *
69 *-----------------------------------------------------------------------------*/
70 char classifierSavePath[256] = "e:/pedestrianDetect-peopleFlow.txt";
71 string buf;
72 vector<string> pos_img_path;
73 vector<string> neg_img_path;
74 ifstream svm_pos_data("pos.txt"); /* 批处理程序生成 */
75 ifstream svm_neg_data("neg.txt"); /* 批处理生成 */
76 while( svm_pos_data )//将训练样本文件依次读取进来
77 {
78 if( getline( svm_pos_data, buf ) )
79 pos_img_path.push_back( buf );
80
81 }
82 while( svm_neg_data )//将训练样本文件依次读取进来
83 {
84 if( getline( svm_neg_data, buf ) )
85 neg_img_path.push_back( buf );
86
87 }
88 cout<<pos_img_path.size()<<"个正样本"<<endl;
89 cout<<neg_img_path.size()<<"个负样本"<<endl;
90 int totalSampleCount=pos_img_path.size()+neg_img_path.size();
91 CvMat *sampleFeaturesMat = cvCreateMat(totalSampleCount , 3780, CV_32FC1);
92 //64*128窗口大小的训练样本,该矩阵将是totalSample*3780
93 //64*64的窗口大小的训练样本,该矩阵将是totalSample*1764
94 cvSetZero(sampleFeaturesMat);
95 CvMat *sampleLabelMat = cvCreateMat(totalSampleCount, 1, CV_32FC1);//样本标识
96 cvSetZero(sampleLabelMat);
97
98 cout<<"************************************************************"<<endl;
99 cout<<"start to training positive samples..."<<endl;
100
101
102
103 for(int i=0; i<pos_img_path.size(); i++)
104 {
105 cv::Mat img = cv::imread(pos_img_path.at(i));
106
107 if( img.data == NULL )
108 {
109 cout<<"positive image sample load error: "<<i<<endl;
110 system("pause");
111 continue;
112 }
113
114 cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
115 vector<float> featureVec;
116
117 hog.compute(img, featureVec, cv::Size(8,8));
118 unsigned int featureVecSize = featureVec.size();
119
120 for (int j=0; j<featureVecSize; j++)
121 {
122 CV_MAT_ELEM( *sampleFeaturesMat, float, i, j ) = featureVec[j];
123 }
124 sampleLabelMat->data.fl[i] = 1;
125 }
126 cout<<"end of training for positive samples..."<<endl;
127
128 cout<<"*********************************************************"<<endl;
129 cout<<"start to train negative samples..."<<endl;
130
131 for (int i=0; i<neg_img_path.size(); i++)
132 {
133
134 cv::Mat img = cv::imread(neg_img_path.at(i));
135 if(img.data == NULL)
136 {
137 cout<<"negative image sample load error: "<<endl;
138 continue;
139 }
140
141 cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
142 vector<float> featureVec;
143
144 hog.compute(img,featureVec,cv::Size(8,8));//计算HOG特征
145 int featureVecSize = featureVec.size();
146
147 for ( int j=0; j<featureVecSize; j ++)
148 {
149 CV_MAT_ELEM( *sampleFeaturesMat, float, i + pos_img_path.size(), j ) = featureVec[ j ];
150 }
151
152 sampleLabelMat->data.fl[ i + pos_img_path.size() ] = -1;
153 }
154
155 cout<<"end of training for negative samples..."<<endl;
156 cout<<"********************************************************"<<endl;
157 cout<<"start to train for SVM classifier..."<<endl;
158
159 CvSVMParams params;
160 params.svm_type = CvSVM::C_SVC;
161 params.kernel_type = CvSVM::LINEAR;
162 params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 1000, FLT_EPSILON);
163 params.C = 0.01;
164
165 Mysvm svm;
166 svm.train( sampleFeaturesMat, sampleLabelMat, NULL, NULL, params ); //用SVM线性分类器训练
167 svm.save(classifierSavePath);
168
169 cvReleaseMat(&sampleFeaturesMat);
170 cvReleaseMat(&sampleLabelMat);
171
172 int supportVectorSize = svm.get_support_vector_count();
173 cout<<"support vector size of SVM:"<<supportVectorSize<<endl;
174 cout<<"************************ end of training for SVM ******************"<<endl;
175
176 CvMat *sv,*alp,*re;//所有样本特征向量
177 sv = cvCreateMat(supportVectorSize , 3780, CV_32FC1);
178 alp = cvCreateMat(1 , supportVectorSize, CV_32FC1);
179 re = cvCreateMat(1 , 3780, CV_32FC1);
180 CvMat *res = cvCreateMat(1 , 1, CV_32FC1);
181
182 cvSetZero(sv);
183 cvSetZero(re);
184
185 for(int i=0; i<supportVectorSize; i++)
186 {
187 memcpy( (float*)(sv->data.fl+i*3780), svm.get_support_vector(i), 3780*sizeof(float));
188 }
189
190 double* alphaArr = svm.get_alpha();
191 int alphaCount = svm.get_alpha_count();
192
193 for(int i=0; i<supportVectorSize; i++)
194 {
195 alp->data.fl[i] = (float)alphaArr[i];
196 }
197 cvMatMul(alp, sv, re);
198
199 int posCount = 0;
200 for (int i=0; i<3780; i++)
201 {
202 re->data.fl[i] *= -1;
203 }
204
205 /*-----------------------------------------------------------------------------
206 * e:/hogSVMDetector-peopleFlow.txt文件中保存的是支持向量,共有3781个值,是一个3781*1的列向量
207 *
208 *
209 *-----------------------------------------------------------------------------*/
210 FILE* fp = fopen("e:/hogSVMDetector-peopleFlow.txt","wb");
211 if( NULL == fp )
212 {
213 return 1;
214 }
215 for(int i=0; i<3780; i++)
216 {
217 fprintf(fp,"%f \n",re->data.fl[i]);
218 }
219 float rho = svm.get_rho();
220 fprintf(fp, "%f", rho);
221 cout<<"e:/hogSVMDetector.txt 保存完毕"<<endl;//保存HOG能识别的分类器
222 fclose(fp);
223
224 return 1;
225 }
226 void my_detect()
227 {
228 CvCapture* cap = cvCreateFileCapture("E:\\test.avi");
229 if (!cap)
230 {
231 cout<<"avi file load error..."<<endl;
232 system("pause");
233 exit(-1);
234 }
235
236 vector<float> x;
237 ifstream fileIn("e:/hogSVMDetector-peopleFlow.txt", ios::in);
238 float val = 0.0f;
239 while(!fileIn.eof())
240 {
241 fileIn>>val;
242 x.push_back(val);
243 }
244 fileIn.close();
245
246 vector<cv::Rect> found;
247 cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
248
249 /*-----------------------------------------------------------------------------
250 *
251 *
252 * 如果setSVMDetector出现问题的话,可能是这个原因:因为默认hog.getDefaultPeopleDetector()
253 * 获取的检测器的大小是3781*1的列向量,所以如果生成的e:/hogSVMDetector-peopleFlow.txt里的大小不等的话
254 * ,读入
255 * 就会出现错误,可能这个函数考虑了运行的速度问题,所以限制了大小为3781*1
256 *
257 * 特别注意:有些童鞋可能生成的特征向量是15876(所以setSVMDetector里的列向量就是15877了与默认的大小不一,assetion就出错了)
258 * ,只要调整下图像的大小和检测窗口的大小,使生成的特征向量为3780就行了,怎么计算,可以参考
259 * 网上其他博客
260 *
261 *-----------------------------------------------------------------------------*/
262 hog.setSVMDetector(x);
263
264 IplImage* img = NULL;
265 cvNamedWindow("img", 0);
266 while(img=cvQueryFrame(cap))
267 {
268 hog.detectMultiScale(img, found, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 2);
269 if (found.size() > 0)
270 {
271 for (int i=0; i<found.size(); i++)
272 {
273 CvRect tempRect = cvRect(found[i].x, found[i].y, found[i].width, found[i].height);
274
275 cvRectangle(img, cvPoint(tempRect.x,tempRect.y),
276 cvPoint(tempRect.x+tempRect.width,tempRect.y+tempRect.height),CV_RGB(255,0,0), 2);
277 }
278 }
279 }
280 cvReleaseCapture(&cap);
281 }
282
283 int main(int argc, char** argv){
284
285 //my_train();
286 //my_detect();
287 vector<float> x;
288 ifstream fileIn("e:/hogSVMDetector-peopleFlow.txt", ios::in); /* 读入支持向量,没必要读入样本的向量 */
289 float val = 0.0f;
290 while(!fileIn.eof())
291 {
292 fileIn>>val;
293 x.push_back(val);
294 }
295 fileIn.close();
296
297 vector<Rect> found, found_filtered;
298 cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
299 hog.setSVMDetector(x);
300
301 Mat img;
302 img=imread("1.jpg",0);
303 hog.detectMultiScale(img, found, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 2);
304 size_t i, j;
305 for( i = 0; i < found.size(); i++ )
306 {
307 Rect r = found[i];
308 for( j = 0; j < found.size(); j++ )
309 if( j != i && (r & found[j]) == r)
310 break;
311 if( j == found.size() )
312 found_filtered.push_back(r);
313 }
314 for( i = 0; i < found_filtered.size(); i++ )
315 {
316 Rect r = found_filtered[i];
317 // the HOG detector returns slightly larger rectangles than the real objects.
318 // so we slightly shrink the rectangles to get a nicer output.
319 r.x += cvRound(r.width*0.1);
320 r.width = cvRound(r.width*0.8);
321 r.y += cvRound(r.height*0.07);
322 r.height = cvRound(r.height*0.8);
323 rectangle(img, r.tl(), r.br(), cv::Scalar(0,255,0), 3);
324 }
325 imshow("people detector", img);
326 waitKey();
327
328 /*cvNamedWindow("img", 0);
329 string testimage="E:\database\picture_resize_pos\resize000r.bmp";
330 Mat img=cv::imread(testimage);
331 hog.detectMultiScale(img, found, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 2);
332 if (found.size() > 0)
333 {
334 printf("found!");
335 }*/
336
337 return 0;
338
339 }
运行效果:
正样本1500多个,负样本400多个,所以效果不咋地,只能呵呵了。
再上一张效果图:(ps:运行的太慢了)