opencv行人检测里遇到的setSVMDetector()问题

参考了博客http://blog.csdn.net/carson2005/article/details/7841443 后,自己动手后发现了一些问题,博客里提到的一些问题没有解决

,是关于为什么图像的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:  http://www.cnblogs.com/yuliyang
 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:运行的太慢了)

posted @ 2013-10-20 11:17  小菜鸟_yang  阅读(8084)  评论(0编辑  收藏  举报