$search
00001 /********************************************************************* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Copyright (c) 2008, Willow Garage, Inc. 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * * Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * * Redistributions in binary form must reproduce the above 00014 * copyright notice, this list of conditions and the following 00015 * disclaimer in the documentation and/or other materials provided 00016 * with the distribution. 00017 * * Neither the name of the Willow Garage nor the names of its 00018 * contributors may be used to endorse or promote products derived 00019 * from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 *********************************************************************/ 00034 00035 #include "laser_processor.h" 00036 #include "calc_leg_features.h" 00037 00038 #include "opencv/cxcore.h" 00039 #include "opencv/cv.h" 00040 #include "opencv/ml.h" 00041 00042 //#include "rosrecord/Player.h" 00043 #include "rosbag/bag.h" 00044 #include <rosbag/view.h> 00045 #include <boost/foreach.hpp> 00046 00047 #include "std_msgs/String.h" 00048 #include "std_msgs/Int32.h" 00049 00050 #include "srs_msgs/PositionMeasurement.h" 00051 #include "sensor_msgs/LaserScan.h" 00052 00053 00054 00055 using namespace std; 00056 using namespace laser_processor; 00057 using namespace ros; 00058 00059 enum LoadType {LOADING_NONE, LOADING_POS, LOADING_NEG, LOADING_TEST, LOADING_BACKGROUND}; 00060 00061 class TrainLegDetector 00062 { 00063 public: 00064 ScanMask mask_; 00065 Background background_; 00066 00067 int mask_count_; // number of added scans to the mask 00068 00069 vector< vector<float> > pos_data_; 00070 vector< vector<float> > neg_data_; 00071 vector< vector<float> > test_data_; 00072 00073 CvRTrees forest; 00074 00075 float connected_thresh_; 00076 00077 int feat_count_; 00078 00079 TrainLegDetector() : mask_count_(0), connected_thresh_(0.06), feat_count_(0) 00080 {} 00081 00082 00083 void loadData(LoadType load, char* file) 00084 { 00085 // printf("In loadData ...\n"); 00086 if (load != LOADING_NONE) 00087 { 00088 switch (load) 00089 { 00090 case LOADING_BACKGROUND: 00091 printf("Loading background data from file: %s\n",file); break; 00092 case LOADING_POS: 00093 printf("Loading positive training data from file: %s\n",file); break; 00094 case LOADING_NEG: 00095 printf("Loading negative training data from file: %s\n",file); break; 00096 case LOADING_TEST: 00097 printf("Loading test data from file: %s\n",file); break; 00098 default: 00099 break; 00100 } 00101 00102 00103 rosbag::Bag bag; 00104 00105 bag.open(file, rosbag::bagmode::Read); 00106 00107 std::vector<std::string> topics; 00108 topics.push_back(std::string("/scan_front")); 00109 // topics.push_back(std::string("/scan_rear")); 00110 00111 00112 rosbag::View view(bag, rosbag::TopicQuery(topics)); 00113 printf("file size %i scans \n", view.size()); 00114 00115 00116 BOOST_FOREACH(rosbag::MessageInstance const m, view) 00117 { 00118 00119 sensor_msgs::LaserScan::ConstPtr scanptr = m.instantiate<sensor_msgs::LaserScan>(); 00120 00121 if (scanptr != NULL) 00122 { 00123 00124 switch (load) 00125 { 00126 case LOADING_BACKGROUND: 00127 loadBackground ( &(sensor_msgs::LaserScan(*scanptr))); 00128 break; 00129 00130 case LOADING_POS: 00131 loadCbBackgroundremoved ( &(sensor_msgs::LaserScan(*scanptr)),&pos_data_); // take out the background 00132 // loadCb ( &(sensor_msgs::LaserScan(*scanptr)),&pos_data_); 00133 break; 00134 00135 case LOADING_NEG: 00136 mask_count_ = 1000; // skips masking building --> no mask 00137 loadCb ( &(sensor_msgs::LaserScan(*scanptr)),&neg_data_); 00138 break; 00139 00140 case LOADING_TEST: 00141 loadCb ( &(sensor_msgs::LaserScan(*scanptr)),&test_data_); 00142 break; 00143 00144 default: 00145 break; 00146 } 00147 } 00148 else 00149 printf ("loadData(), scanptr is NULL"); 00150 00151 } 00152 00153 bag.close(); 00154 00155 } // if (load != LOADING_NONE) 00156 00157 } 00158 00159 void loadBackground(sensor_msgs::LaserScan* scan) 00160 { 00161 // printf (","); 00162 background_.addScan(*scan, 0.3); // scan + treshhold to know whether to merge them or not 00163 } 00164 00165 void loadCb(sensor_msgs::LaserScan* scan, vector< vector<float> >* data) 00166 { 00167 // printf ("."); 00168 00169 if (mask_count_++ < 20) // for the first 20 scans it only builds the mask (start from the first scan and reduce it) 00170 { 00171 mask_.addScan(*scan); 00172 } 00173 else // and then does the processing 00174 { 00175 ScanProcessor processor(*scan,mask_); //doesn't remove the backgrond 00176 processor.splitConnected(connected_thresh_); 00177 processor.removeLessThan(5); 00178 00179 for (list<SampleSet*>::iterator i = processor.getClusters().begin(); 00180 i != processor.getClusters().end(); 00181 i++) 00182 data->push_back( calcLegFeatures(*i, *scan)); 00183 } 00184 } 00185 00186 void loadCbBackgroundremoved(sensor_msgs::LaserScan* scan, vector< vector<float> >* data) 00187 { 00188 // printf ("."); 00189 00190 if (mask_count_++ < 20) // for the first 20 scans it only builds the mask (start from the first scan and reduce it) 00191 { 00192 mask_.addScan(*scan); 00193 } 00194 else // and then does the processing 00195 { 00196 ScanProcessor processor(*scan,mask_); // do not remove background 00197 //ScanProcessor processor(*scan,mask_,background_); //remove the background as well 00198 processor.splitConnected(connected_thresh_); 00199 processor.removeLessThan(5); 00200 00201 for (list<SampleSet*>::iterator i = processor.getClusters().begin(); 00202 i != processor.getClusters().end(); 00203 i++) 00204 data->push_back( calcLegFeatures(*i, *scan)); 00205 } 00206 } 00207 00208 void traincl() 00209 { 00210 // printf("In traincl()...."); 00211 int sample_size = pos_data_.size() + neg_data_.size(); 00212 feat_count_ = pos_data_[0].size(); 00213 00214 CvMat* cv_data = cvCreateMat( sample_size, feat_count_, CV_32FC1); // sample data 00215 CvMat* cv_resp = cvCreateMat( sample_size, 1, CV_32S); // responces 00216 00217 // Put positive data in opencv format. 00218 int j = 0; 00219 for (vector< vector<float> >::iterator i = pos_data_.begin(); 00220 i != pos_data_.end(); 00221 i++) 00222 { 00223 float* data_row = (float*)(cv_data->data.ptr + cv_data->step*j); 00224 for (int k = 0; k < feat_count_; k++) 00225 data_row[k] = (*i)[k]; 00226 00227 cv_resp->data.i[j] = 1; // positive responce 00228 j++; 00229 } 00230 00231 // Put negative data in opencv format. 00232 for (vector< vector<float> >::iterator i = neg_data_.begin(); 00233 i != neg_data_.end(); 00234 i++) 00235 { 00236 float* data_row = (float*)(cv_data->data.ptr + cv_data->step*j); 00237 for (int k = 0; k < feat_count_; k++) 00238 data_row[k] = (*i)[k]; 00239 00240 cv_resp->data.i[j] = -1; // negative responce 00241 j++; 00242 } 00243 00244 CvMat* var_type = cvCreateMat( 1, feat_count_ + 1, CV_8U ); 00245 cvSet( var_type, cvScalarAll(CV_VAR_ORDERED)); 00246 cvSetReal1D( var_type, feat_count_, CV_VAR_CATEGORICAL ); 00247 00248 float priors[] = {1.0, 1.0}; 00249 00250 CvRTParams fparam(8, // _max_depth: max_categories until pre-clustering 00251 20, // _min_sample_count: Don’t split a node if less 00252 0, // _regression_accuracy: One of the “stop splitting” criteria 00253 false, // _use_surrogates: Alternate splits for missing data 00254 10, // _max_categories: 00255 priors, // priors 00256 false, // _calc_var_importance 00257 5, // _nactive_vars 00258 50, // max_tree_count 00259 0.001f, // forest_accuracy 00260 CV_TERMCRIT_ITER // termcrit_type 00261 ); 00262 fparam.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 0.1); 00263 00264 forest.train( cv_data, // train_data 00265 CV_ROW_SAMPLE, // tflag --> each row is a data point consisting of a vector of features that make up the columns of the matrix 00266 cv_resp, // responses --> a floating-point vector of values to be predicted given the data features 00267 0, // comp_idx 00268 0, // sample_idx 00269 var_type, // var_type 00270 0, // missing_mask 00271 fparam); // the structure from above 00272 00273 00274 cvReleaseMat(&cv_data); 00275 cvReleaseMat(&cv_resp); 00276 cvReleaseMat(&var_type); 00277 } 00278 00279 void test() 00280 { 00281 CvMat* tmp_mat = cvCreateMat(1,feat_count_,CV_32FC1); 00282 00283 int pos_right = 0; 00284 int pos_total = 0; 00285 for (vector< vector<float> >::iterator i = pos_data_.begin(); 00286 i != pos_data_.end(); 00287 i++) 00288 { 00289 for (int k = 0; k < feat_count_; k++) 00290 tmp_mat->data.fl[k] = (float)((*i)[k]); 00291 if (forest.predict( tmp_mat) > 0) 00292 pos_right++; 00293 pos_total++; 00294 } 00295 00296 int neg_right = 0; 00297 int neg_total = 0; 00298 for (vector< vector<float> >::iterator i = neg_data_.begin(); 00299 i != neg_data_.end(); 00300 i++) 00301 { 00302 for (int k = 0; k < feat_count_; k++) 00303 tmp_mat->data.fl[k] = (float)((*i)[k]); 00304 if (forest.predict( tmp_mat ) < 0) 00305 neg_right++; 00306 neg_total++; 00307 } 00308 00309 int test_right = 0; 00310 int test_total = 0; 00311 for (vector< vector<float> >::iterator i = test_data_.begin(); 00312 i != test_data_.end(); 00313 i++) 00314 { 00315 for (int k = 0; k < feat_count_; k++) 00316 tmp_mat->data.fl[k] = (float)((*i)[k]); 00317 if (forest.predict( tmp_mat ) > 0) 00318 test_right++; 00319 test_total++; 00320 } 00321 00322 printf(" Pos train set: %d/%d %g\n",pos_right, pos_total, (float)(pos_right)/pos_total); 00323 printf(" Neg train set: %d/%d %g\n",neg_right, neg_total, (float)(neg_right)/neg_total); 00324 printf(" Test set: %d/%d %g\n",test_right, test_total, (float)(test_right)/test_total); 00325 00326 cvReleaseMat(&tmp_mat); 00327 00328 } 00329 00330 void save(char* file) 00331 { 00332 forest.save(file); 00333 } 00334 }; 00335 00336 int main(int argc, char **argv) 00337 { 00338 if (argc < 2) 00339 { 00340 printf("Usage: train_leg_detector --background background_file --train file1 --neg file2 --test file3 --save conf_file\n"); 00341 exit (0); 00342 } 00343 00344 TrainLegDetector tld; 00345 00346 LoadType loading = LOADING_NONE; 00347 00348 char save_file[100]; 00349 save_file[0] = 0; 00350 00351 printf("Loading data...\n"); 00352 for (int i = 1; i < argc; i++) 00353 { 00354 00355 if (!strcmp(argv[i],"--background")) 00356 loading = LOADING_BACKGROUND; 00357 else if (!strcmp(argv[i],"--train")) 00358 loading = LOADING_POS; 00359 else if (!strcmp(argv[i],"--neg")) 00360 loading = LOADING_NEG; 00361 else if (!strcmp(argv[i],"--test")) 00362 loading = LOADING_TEST; 00363 else if (!strcmp(argv[i],"--save")) 00364 { 00365 if (++i < argc) 00366 strncpy(save_file,argv[i],100); 00367 continue; 00368 } 00369 else 00370 tld.loadData(loading, argv[i]); 00371 } 00372 00373 printf("Training classifier...\n"); 00374 00375 tld.traincl(); 00376 00377 printf("Evlauating classifier...\n"); 00378 tld.test(); 00379 00380 if (strlen(save_file) > 0) 00381 { 00382 printf("Saving classifier as: %s\n", save_file); 00383 tld.save(save_file); 00384 } 00385 }