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:运行的太慢了)
作者:小菜鸟_yang
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。