參考了博客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:運行的太慢了)