00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #include "Image/OpenCVUtil.H"
00045
00046
00047 #include "Neuro/GistEstimatorContextBased.H"
00048
00049
00050 #include "Neuro/StdBrain.H"
00051 #include "Neuro/NeuroOpts.H"
00052 #include "Neuro/NeuroSimEvents.H"
00053
00054 #include "Media/SimFrameSeries.H"
00055 #include "Media/MediaOpts.H"
00056
00057 #include "Simulation/SimEventQueue.H"
00058 #include "Simulation/SimEventQueueConfigurator.H"
00059
00060 #include "Channels/ChannelOpts.H"
00061 #include "Component/ModelManager.H"
00062 #include "Component/ModelOptionDef.H"
00063
00064 #include "Image/MathOps.H"
00065 #include "Image/MatrixOps.H"
00066 #include "Image/Point2D.H"
00067
00068 #include "nub/ref.h"
00069
00070 #ifndef HAVE_OPENCV // fake OpenCV API so as to not break builds
00071
00072 namespace {
00073
00074 struct CvMat {int rows, cols, type ;} ;
00075
00076 inline CvMat* cvCreateMat(int, int, int) {return 0 ;}
00077 inline void cvReleaseMat(CvMat**) {}
00078 inline double cvmGet(CvMat*, int, int) {return 0 ;}
00079 inline void cvmSet(CvMat*, int, int, double) {}
00080 inline void cvTranspose(const CvMat*, CvMat*) {}
00081
00082 #define CV_32FC1 0
00083 inline int CV_MAT_TYPE(int) {return 0 ;}
00084 #define CV_MAT_ELEM(matrix, type, row, col) (type(0))
00085
00086 #define CV_PCA_DATA_AS_COL 0
00087 inline void cvCalcPCA(const CvMat*, CvMat*, CvMat*, CvMat*, int) {}
00088
00089 }
00090
00091 #endif // OpenCV availability check
00092
00093
00094 #include <fstream>
00095 #include <sstream>
00096 #include <ios>
00097 #include <numeric>
00098 #include <algorithm>
00099 #include <functional>
00100 #include <map>
00101 #include <vector>
00102 #include <iterator>
00103 #include <stdexcept>
00104 #include <utility>
00105
00106
00107
00108
00109
00110
00111 #ifndef GECB_NUM_PRINCIPAL_COMPONENTS
00112 #define GECB_NUM_PRINCIPAL_COMPONENTS 80
00113 #endif
00114
00115
00116
00117 namespace {
00118
00119
00120 typedef Image<double> GistVector ;
00121 typedef std::map<int, GistVector> TrainingDB ;
00122 typedef TrainingDB::value_type TrainingDBEntry ;
00123
00124
00125 class OpenCVMatrix ;
00126 CvMat* load_training_vectors(const std::string& file_name, int M, int N) ;
00127 CvMat* pca(const OpenCVMatrix& data, int num_principal_components) ;
00128
00129
00130 typedef std::pair<std::string, GistVector> InputImageData ;
00131 void classify_image(const InputImageData&, const TrainingDB&,
00132 const std::string& results_file) ;
00133
00134
00135 void save(const OpenCVMatrix&, const std::string& file_name) ;
00136
00137 void append(const Image<double>&,
00138 const std::string& file_name,
00139 const std::string& image_name = std::string()) ;
00140 Image<double> load_image(const std::string& file_name,
00141 int width, int height) ;
00142 std::ostream& operator<<(std::ostream&, const Image<double>&) ;
00143 std::istream& operator>>(std::istream&, Image<double>&) ;
00144
00145 TrainingDB load_training_database(const std::string& file_name) ;
00146
00147 std::string getline(std::istream&) ;
00148
00149
00150 int count_lines(const std::string& file_name) ;
00151 template<typename T> std::string to_string(const T&) ;
00152
00153 }
00154
00155
00156
00157
00158 namespace {
00159
00160 class OpenCVMatrix {
00161 CvMat* matrix ;
00162 public :
00163 OpenCVMatrix(int num_rows, int num_cols, int type) ;
00164 OpenCVMatrix(CvMat*) ;
00165 ~OpenCVMatrix() ;
00166
00167 int num_rows() const {return matrix->rows ;}
00168 int num_cols() const {return matrix->cols ;}
00169 int type() const {return CV_MAT_TYPE(matrix->type) ;}
00170
00171 template<typename T>
00172 T get(int i, int j) const {return CV_MAT_ELEM(*matrix, T, i, j) ;}
00173
00174 operator CvMat*() const {return matrix ;}
00175 } ;
00176
00177 OpenCVMatrix::OpenCVMatrix(int num_rows, int num_cols, int type)
00178 : matrix(cvCreateMat(num_rows, num_cols, type))
00179 {
00180 if (! matrix)
00181 throw std::runtime_error("unable to create OpenCV matrix") ;
00182 }
00183
00184 OpenCVMatrix::OpenCVMatrix(CvMat* M)
00185 : matrix(M)
00186 {
00187 if (! matrix)
00188 throw std::runtime_error("cannot create empty/null matrix") ;
00189 }
00190
00191 OpenCVMatrix::~OpenCVMatrix()
00192 {
00193 cvReleaseMat(& matrix) ;
00194 }
00195
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205 namespace {
00206
00207 const ModelOptionCateg MOC_GECB = {
00208 MOC_SORTPRI_3,
00209 "Options specific to the context-based gist program",
00210 } ;
00211
00212
00213
00214
00215 #ifndef GECB_DEFAULT_TRAINING_VECTORS_FILE
00216 #define GECB_DEFAULT_TRAINING_VECTORS_FILE "gecb_training_vectors.txt"
00217 #endif
00218
00219 const ModelOptionDef OPT_TrainingVectors = {
00220 MODOPT_ARG_STRING, "TrainingVectors", & MOC_GECB, OPTEXP_CORE,
00221 "This option specifies the name of the file where the training vectors\n"
00222 "should be accumulated or read from. This is a plain text file containing\n"
00223 "the training vectors matrix that will be fed into the PCA procedure.\n"
00224 "Each line of this file will contain a row of \"raw\" (i.e., 384-\n"
00225 "dimensional) gist vectors. For PCA, these rows will be read in as the\n"
00226 "columns of the data matrix.\n",
00227 "training-vectors", '\0', "training-vectors-file",
00228 GECB_DEFAULT_TRAINING_VECTORS_FILE,
00229 } ;
00230
00231
00232
00233
00234
00235 #ifndef GECB_DEFAULT_PCA_MATRIX_FILE
00236 #define GECB_DEFAULT_PCA_MATRIX_FILE "gecb_pca_matrix.txt"
00237 #endif
00238
00239 const ModelOptionDef OPT_PCAMatrix = {
00240 MODOPT_ARG_STRING, "PCAMatrix", & MOC_GECB, OPTEXP_CORE,
00241 "This option specifies the name of the file in which the 384x80 PCA\n"
00242 "transformation matrix is (or will be) stored. \"Raw\" 384-dimensional\n"
00243 " gist vectors can be reduced to 80 dimensions by muliplying with this\n"
00244 "matrix. The PCA transformation matrix is stored in a plain text file\n"
00245 "with each line containing one row of the matrix.\n",
00246 "pca-matrix", '\0', "pca-matrix-file",
00247 GECB_DEFAULT_PCA_MATRIX_FILE,
00248 } ;
00249
00250
00251
00252
00253
00254
00255
00256
00257 #ifndef GECB_DEFAULT_IMAGE_NAME
00258 #define GECB_DEFAULT_IMAGE_NAME "some_image"
00259 #endif
00260 #ifndef GECB_DEFAULT_SEGMENT_NUMBER
00261 #define GECB_DEFAULT_SEGMENT_NUMBER "0"
00262 #endif
00263
00264 const ModelOptionDef OPT_ImageName = {
00265 MODOPT_ARG_STRING, "ImageName", & MOC_GECB, OPTEXP_CORE,
00266 "This option specifies the \"root\" name of an entry in the training\n"
00267 "set or the results file. The image number will be automatically\n"
00268 "appended to this \"root\" name. The training database is a plain text\n"
00269 "file containing one entry per line. The first field specifies the name\n"
00270 "plus number of the entry (e.g., foo.1, foo.2, bar.1, and so on). The\n"
00271 "second field is the segment number for this image. The remaining fields\n"
00272 "are the 80 numbers making up the image's gist vector.\n\n"
00273 "In classification mode, this option specifies the name of the input\n"
00274 "image's gist vector that is written to the results file.\n",
00275 "image-name", '\0', "image-name-root",
00276 GECB_DEFAULT_IMAGE_NAME,
00277 } ;
00278
00279 const ModelOptionDef OPT_SegmentNumber = {
00280 MODOPT_ARG_STRING, "SegmentNumber", & MOC_GECB, OPTEXP_CORE,
00281 "This option specifies the segment number for an image in the training\n"
00282 "set. The segment number is used in the third phase of training to\n"
00283 "compute the mean 80-D gist vectors for each segment and during\n"
00284 "classification to ascertain the segment number for each input image.\n",
00285 "segment-number", '\0', "image-segment-number",
00286 GECB_DEFAULT_SEGMENT_NUMBER,
00287 } ;
00288
00289
00290
00291
00292 #ifndef GECB_DEFAULT_TRAINING_SET
00293 #define GECB_DEFAULT_TRAINING_SET "gecb_training_set.txt"
00294 #endif
00295
00296 const ModelOptionDef OPT_TrainingSet = {
00297 MODOPT_ARG_STRING, "TrainingSet", & MOC_GECB, OPTEXP_CORE,
00298 "This option specifies the name of the training set, a plain text\n"
00299 "file containing one entry per line. The first field specifies the name\n"
00300 "plus number of the entry (e.g., foo.1, foo.2, bar.1, and so on). The\n"
00301 "second field is the segment number for this image. And the remaining\n"
00302 "fields are the 80 numbers that make up the image's gist vector.\n",
00303 "training-set", '\0', "training-set-file",
00304 GECB_DEFAULT_TRAINING_SET,
00305 } ;
00306
00307
00308
00309 #ifndef GECB_DEFAULT_TRAINING_DATABASE
00310 #define GECB_DEFAULT_TRAINING_DATABASE "gecb_training_db.txt"
00311 #endif
00312
00313 const ModelOptionDef OPT_TrainingDB = {
00314 MODOPT_ARG_STRING, "TrainingDB", & MOC_GECB, OPTEXP_CORE,
00315 "This option specifies the name of the training database, a plain text\n"
00316 "file containing one entry per line. The first field specifies the\n"
00317 "segment number. And the remaining fields are the 80 numbers that make\n"
00318 "up the segment's mean gist vector.\n",
00319 "training-db", '\0', "training-db-file",
00320 GECB_DEFAULT_TRAINING_DATABASE,
00321 } ;
00322
00323
00324
00325 #ifndef GECB_DEFAULT_CLASSIFICATION_RESULTS_FILE
00326 #define GECB_DEFAULT_CLASSIFICATION_RESULTS_FILE "gecb_classifications.txt"
00327 #endif
00328
00329 const ModelOptionDef OPT_ResultsFile = {
00330 MODOPT_ARG_STRING, "ResultsFile", & MOC_GECB, OPTEXP_CORE,
00331 "This option specifies the name of the classification results file,\n"
00332 "a plain text file containing one result entry per line. The first\n"
00333 "field specifies the name plus number of the input image, (e.g., foo.1,\n"
00334 "foo.2, bar.1, and so on). Then come the numbers of the top five matching\n"
00335 "segments from the training database.\n",
00336 "results-file", '\0', "classification-results-file",
00337 GECB_DEFAULT_CLASSIFICATION_RESULTS_FILE,
00338 } ;
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373 #ifndef GECB_ACCUMULATE_CMD
00374 #define GECB_ACCUMULATE_CMD "accumulate"
00375 #endif
00376 #ifndef GECB_PCA_CMD
00377 #define GECB_PCA_CMD "pca"
00378 #endif
00379 #ifndef GECB_TRAIN_CMD
00380 #define GECB_TRAIN_CMD "train"
00381 #endif
00382 #ifndef GECB_MEANS_CMD
00383 #define GECB_MEANS_CMD "means"
00384 #endif
00385 #ifndef GECB_CLASSIFY_CMD
00386 #define GECB_CLASSIFY_CMD "classify"
00387 #endif
00388
00389
00390 #ifndef GECB_ACTIONS
00391 #define GECB_ACTIONS ("{"GECB_ACCUMULATE_CMD"|"GECB_PCA_CMD"|"\
00392 GECB_TRAIN_CMD"|"GECB_MEANS_CMD"|"\
00393 GECB_CLASSIFY_CMD"}")
00394 #endif
00395
00396 }
00397
00398
00399
00400 namespace {
00401
00402
00403
00404
00405 class ContextBasedSimulation {
00406 ModelManager model_manager ;
00407 nub::soft_ref<SimEventQueueConfigurator> configurator ;
00408 nub::soft_ref<StdBrain> brain ;
00409 nub::ref<SimInputFrameSeries> input_frame_series ;
00410
00411
00412 OModelParam<std::string> tv_option ;
00413 OModelParam<std::string> pm_option ;
00414 OModelParam<std::string> ts_option ;
00415 OModelParam<std::string> td_option ;
00416 OModelParam<std::string> rf_option ;
00417 OModelParam<std::string> in_option ;
00418 OModelParam<std::string> sn_option ;
00419
00420 public :
00421 ContextBasedSimulation(const std::string& model_name) ;
00422 void parse_command_line(int argc, const char* argv[]) ;
00423 void run() ;
00424 ~ContextBasedSimulation() ;
00425
00426 private :
00427
00428 typedef void (ContextBasedSimulation::*Action)() ;
00429 typedef std::map<std::string, Action> ActionMap ;
00430 ActionMap action_map ;
00431
00432 void accumulate_training_vectors() ;
00433 void compute_pca_matrix() ;
00434 void compute_training_vectors() ;
00435 void compute_segment_means() ;
00436 void classify_input_images() ;
00437
00438
00439 std::string training_vectors_file() {return tv_option.getVal() ;}
00440 std::string pca_matrix_file() {return pm_option.getVal() ;}
00441 std::string training_set() {return ts_option.getVal() ;}
00442 std::string training_database() {return td_option.getVal() ;}
00443 std::string results_file() {return rf_option.getVal() ;}
00444 std::string image_name() {return in_option.getVal() ;}
00445 std::string segment_number() {return sn_option.getVal() ;}
00446 } ;
00447
00448
00449
00450 ContextBasedSimulation::ContextBasedSimulation(const std::string& model_name)
00451 : model_manager(model_name),
00452 configurator(new SimEventQueueConfigurator(model_manager)),
00453 brain(new StdBrain(model_manager)),
00454 input_frame_series(new SimInputFrameSeries(model_manager)),
00455 tv_option(& OPT_TrainingVectors, & model_manager),
00456 pm_option(& OPT_PCAMatrix, & model_manager),
00457 ts_option(& OPT_TrainingSet, & model_manager),
00458 td_option(& OPT_TrainingDB, & model_manager),
00459 rf_option(& OPT_ResultsFile, & model_manager),
00460 in_option(& OPT_ImageName, & model_manager),
00461 sn_option(& OPT_SegmentNumber, & model_manager)
00462 {
00463 model_manager.addSubComponent(configurator) ;
00464 model_manager.addSubComponent(brain) ;
00465 model_manager.addSubComponent(input_frame_series) ;
00466
00467 typedef ContextBasedSimulation me ;
00468 action_map[GECB_ACCUMULATE_CMD] = & me::accumulate_training_vectors ;
00469 action_map[GECB_PCA_CMD] = & me::compute_pca_matrix ;
00470 action_map[GECB_TRAIN_CMD] = & me::compute_training_vectors ;
00471 action_map[GECB_MEANS_CMD] = & me::compute_segment_means ;
00472 action_map[GECB_CLASSIFY_CMD] = & me::classify_input_images ;
00473 }
00474
00475
00476
00477
00478
00479 void ContextBasedSimulation::parse_command_line(int argc, const char* argv[])
00480 {
00481 model_manager.setOptionValString(& OPT_SingleChannelSaveRawMaps, "true") ;
00482 model_manager.setOptionValString(& OPT_GistEstimatorType, "ContextBased") ;
00483 model_manager.setOptionValString(& OPT_NumOrientations, "6") ;
00484
00485 model_manager.setOptionValString(& OPT_TrainingVectors,
00486 GECB_DEFAULT_TRAINING_VECTORS_FILE) ;
00487 model_manager.setOptionValString(& OPT_PCAMatrix,
00488 GECB_DEFAULT_PCA_MATRIX_FILE) ;
00489 model_manager.setOptionValString(& OPT_TrainingSet,
00490 GECB_DEFAULT_TRAINING_SET) ;
00491 model_manager.setOptionValString(& OPT_TrainingDB,
00492 GECB_DEFAULT_TRAINING_DATABASE) ;
00493 model_manager.setOptionValString(& OPT_ResultsFile,
00494 GECB_DEFAULT_CLASSIFICATION_RESULTS_FILE) ;
00495 model_manager.setOptionValString(& OPT_ImageName,
00496 GECB_DEFAULT_IMAGE_NAME) ;
00497 model_manager.setOptionValString(& OPT_SegmentNumber,
00498 GECB_DEFAULT_SEGMENT_NUMBER) ;
00499
00500 if (! model_manager.parseCommandLine(argc, argv, GECB_ACTIONS, 1, 1))
00501 throw std::runtime_error("command line parse error") ;
00502 }
00503
00504
00505
00506 void ContextBasedSimulation::run()
00507 {
00508 std::string cmd(model_manager.getExtraArg(0)) ;
00509 ActionMap::iterator action = action_map.find(cmd) ;
00510 if (action == action_map.end())
00511 throw std::runtime_error(cmd + ": sorry, unknown action") ;
00512 (this->*(action->second))() ;
00513 }
00514
00515
00516
00517
00518
00519 class ModelManagerStarter {
00520 ModelManager& mgr ;
00521 public :
00522 ModelManagerStarter(ModelManager& m) : mgr(m) {mgr.start() ;}
00523 ~ModelManagerStarter() {mgr.stop() ;}
00524 } ;
00525
00526
00527
00528
00529
00530 void ContextBasedSimulation::accumulate_training_vectors()
00531 {
00532 ModelManagerStarter M(model_manager) ;
00533
00534 LFATAL("fixme");
00535 nub::soft_ref<GistEstimatorContextBased> ge;
00536
00537 if (ge.isInvalid())
00538 throw std::runtime_error("can only use GistEstimatorContextBased") ;
00539
00540 nub::ref<SimEventQueue> event_queue = configurator->getQ() ;
00541 for(;;)
00542 {
00543 try
00544 {
00545 SeC<SimEventGistOutput> gist_out =
00546 event_queue->check<SimEventGistOutput>(brain.get(),
00547 SEQ_UNMARKED | SEQ_MARK,
00548 ge.get()) ;
00549 if (gist_out)
00550 append(ge->getGist(), training_vectors_file()) ;
00551 if (event_queue->evolve() != SIM_CONTINUE)
00552 break ;
00553 }
00554 catch (lfatal_exception&)
00555 {
00556 return ;
00557 }
00558 }
00559 }
00560
00561
00562
00563
00564 void ContextBasedSimulation::compute_pca_matrix()
00565 {
00566 LINFO("MVN: counting lines in %s", training_vectors_file().c_str()) ;
00567 const int cols = count_lines(training_vectors_file()) ;
00568 const int rows = static_cast<int>(GistEstimatorContextBased::NUM_FEATURES) ;
00569
00570 LINFO("MVN: reading %d training vectors from %s",
00571 cols, training_vectors_file().c_str()) ;
00572 OpenCVMatrix training_vectors =
00573 load_training_vectors(training_vectors_file(), rows, cols) ;
00574
00575 LINFO("MVN: doing PCA on training vectors to get %d principal components",
00576 GECB_NUM_PRINCIPAL_COMPONENTS) ;
00577 OpenCVMatrix pca_matrix = pca(training_vectors,
00578 GECB_NUM_PRINCIPAL_COMPONENTS) ;
00579
00580 LINFO("MVN: PCA done; saving PCA transformation matrix to %s",
00581 pca_matrix_file().c_str()) ;
00582 save(pca_matrix, pca_matrix_file()) ;
00583 }
00584
00585
00586
00587
00588
00589
00590
00591
00592 void ContextBasedSimulation::compute_training_vectors()
00593 {
00594 ModelManagerStarter M(model_manager) ;
00595
00596 LFATAL("fixme");
00597 nub::soft_ref<GistEstimatorContextBased> ge;
00598
00599 if (ge.isInvalid())
00600 throw std::runtime_error("can only use GistEstimatorContextBased") ;
00601
00602 Image<double> W = load_image(pca_matrix_file(),
00603 GECB_NUM_PRINCIPAL_COMPONENTS,
00604 count_lines(pca_matrix_file())) ;
00605 LINFO("MVN: loaded %dx%d PCA transformation matrix from %s",
00606 W.getHeight(), W.getWidth(), pca_matrix_file().c_str()) ;
00607
00608 int i = 1 ;
00609 nub::ref<SimEventQueue> event_queue = configurator->getQ() ;
00610 for(;;)
00611 {
00612 try
00613 {
00614 SeC<SimEventGistOutput> gist_out =
00615 event_queue->check<SimEventGistOutput>(brain.get(),
00616 SEQ_UNMARKED | SEQ_MARK,
00617 ge.get()) ;
00618 if (gist_out)
00619 append(vmMult(ge->getGist(), W),
00620 training_set(),
00621 image_name() + to_string(i++) + " " + segment_number()) ;
00622 if (event_queue->evolve() != SIM_CONTINUE)
00623 break ;
00624 }
00625 catch (lfatal_exception&)
00626 {
00627 return ;
00628 }
00629 }
00630 }
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640 void ContextBasedSimulation::compute_segment_means()
00641 {
00642 typedef std::pair<int, GistVector> SegmentInfo ;
00643 typedef std::map<int, SegmentInfo> MeansMap ;
00644 MeansMap means ;
00645
00646 LINFO("reading training set data from %s", training_set().c_str()) ;
00647 std::ifstream ifs(training_set().c_str()) ;
00648 for(;;)
00649 {
00650 try
00651 {
00652 std::istringstream line(getline(ifs)) ;
00653
00654 std::string name ; int segment ;
00655 GistVector G(GECB_NUM_PRINCIPAL_COMPONENTS, 1, ZEROS) ;
00656 line >> name >> segment >> G ;
00657
00658 MeansMap::iterator it = means.find(segment) ;
00659 if (it == means.end())
00660 {
00661 means.insert(std::make_pair(segment, SegmentInfo(1, G))) ;
00662 }
00663 else
00664 {
00665 SegmentInfo& I = it->second ;
00666 ++I.first ;
00667 I.second += G ;
00668 }
00669 }
00670 catch (std::exception&)
00671 {
00672 break ;
00673 }
00674 }
00675
00676 LINFO("computing gist vector averages for each segment and saving to %s",
00677 training_database().c_str()) ;
00678 std::ofstream ofs(training_database().c_str()) ;
00679 for (MeansMap::iterator it = means.begin(); it != means.end(); ++it)
00680 {
00681 SegmentInfo& I = it->second ;
00682 I.second /= I.first ;
00683 ofs << it->first << ' ' << I.second ;
00684 }
00685 }
00686
00687
00688
00689
00690
00691 void ContextBasedSimulation::classify_input_images()
00692 {
00693 ModelManagerStarter M(model_manager) ;
00694
00695 LFATAL("fixme");
00696 nub::soft_ref<GistEstimatorContextBased> ge;
00697
00698 if (ge.isInvalid())
00699 throw std::runtime_error("can only use GistEstimatorContextBased") ;
00700
00701 Image<double> W = load_image(pca_matrix_file(),
00702 GECB_NUM_PRINCIPAL_COMPONENTS,
00703 count_lines(pca_matrix_file())) ;
00704 LINFO("MVN: loaded %dx%d PCA transformation matrix from %s",
00705 W.getHeight(), W.getWidth(), pca_matrix_file().c_str()) ;
00706
00707 TrainingDB training_db = load_training_database(training_database()) ;
00708 LINFO("MVN: loaded %d training vectors from %s",
00709 int(training_db.size()), training_database().c_str()) ;
00710
00711 int i = 1 ;
00712 nub::ref<SimEventQueue> event_queue = configurator->getQ() ;
00713 for(;;)
00714 {
00715 try
00716 {
00717 SeC<SimEventGistOutput> gist_out =
00718 event_queue->check<SimEventGistOutput>(brain.get(),
00719 SEQ_UNMARKED | SEQ_MARK,
00720 ge.get()) ;
00721 if (gist_out)
00722 classify_image(std::make_pair(image_name() + to_string(i++),
00723 vmMult(ge->getGist(), W)),
00724 training_db, results_file()) ;
00725 if (event_queue->evolve() != SIM_CONTINUE)
00726 break ;
00727 }
00728 catch (lfatal_exception&)
00729 {
00730 return ;
00731 }
00732 }
00733 }
00734
00735
00736
00737
00738 ContextBasedSimulation::~ContextBasedSimulation() {}
00739
00740 }
00741
00742
00743
00744 #ifdef HAVE_OPENCV
00745
00746 int main(int argc, const char* argv[])
00747 {
00748 MYLOGVERB = LOG_INFO ;
00749 try
00750 {
00751 ContextBasedSimulation S("train-gecb Model") ;
00752 S.parse_command_line(argc, argv) ;
00753 S.run() ;
00754 }
00755 catch (std::exception& e)
00756 {
00757 LFATAL("%s", e.what()) ;
00758 return 1 ;
00759 }
00760 return 0 ;
00761 }
00762
00763 #else
00764
00765 int main()
00766 {
00767 LINFO("Sorry, this program needs OpenCV.") ;
00768 return 1 ;
00769 }
00770
00771 #endif
00772
00773
00774
00775 namespace {
00776
00777
00778
00779 CvMat* load_training_vectors(const std::string& file_name, int M, int N)
00780 {
00781 CvMat* data = cvCreateMat(M, N, CV_32FC1) ;
00782
00783 double d ;
00784 std::ifstream ifs(file_name.c_str()) ;
00785 for (int j = 0; j < N; ++j)
00786 for (int i = 0; i < M; ++i) {
00787 if (! ifs) {
00788 cvReleaseMat(& data) ;
00789 throw std::runtime_error(file_name + ": out of data?!?") ;
00790 }
00791 ifs >> d ;
00792 cvmSet(data, i, j, d) ;
00793 }
00794
00795 return data ;
00796 }
00797
00798
00799
00800 CvMat* pca(const OpenCVMatrix& data, int D)
00801 {
00802 OpenCVMatrix means = cvCreateMat(data.num_rows(), 1, CV_32FC1) ;
00803 OpenCVMatrix eigenvalues = cvCreateMat(D, 1, CV_32FC1) ;
00804 OpenCVMatrix eigenvectors = cvCreateMat(D, data.num_rows(), CV_32FC1) ;
00805
00806 cvCalcPCA(data, means, eigenvalues, eigenvectors, CV_PCA_DATA_AS_COL) ;
00807
00808 CvMat* pca_matrix = cvCreateMat(data.num_rows(), D, CV_32FC1) ;
00809 cvTranspose(eigenvectors, pca_matrix) ;
00810 return pca_matrix ;
00811 }
00812
00813 }
00814
00815
00816
00817
00818
00819
00820
00821
00822 namespace {
00823
00824
00825
00826
00827
00828
00829 typedef std::pair<int, double> SegmentDistance ;
00830
00831
00832
00833 bool distance_cmp(const SegmentDistance& L, const SegmentDistance& R)
00834 {
00835 return L.second < R.second ;
00836 }
00837
00838
00839
00840
00841 std::ostream& operator<<(std::ostream& os, const SegmentDistance& D)
00842 {
00843 return os << D.first ;
00844 }
00845
00846
00847
00848
00849 struct euclidean_distance
00850 : public std::binary_function<TrainingDBEntry, GistVector, SegmentDistance>
00851 {
00852 SegmentDistance
00853 operator()(const TrainingDBEntry& E, const GistVector& input) const {
00854 return std::make_pair(E.first, distance<float>(input, E.second)) ;
00855 }
00856 } ;
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869 void classify_image(const InputImageData& input, const TrainingDB& db,
00870 const std::string& results_file)
00871 {
00872 std::vector<SegmentDistance> distances ;
00873 std::transform(db.begin(), db.end(), std::back_inserter(distances),
00874 std::bind2nd(euclidean_distance(), input.second)) ;
00875 std::sort(distances.begin(), distances.end(), distance_cmp) ;
00876
00877 std::ofstream ofs(results_file.c_str(), std::ios::out | std::ios::app) ;
00878 ofs << input.first << ' ' ;
00879
00880
00881 for (unsigned int i = 0; i < distances.size() && i < 5; ++i)
00882 ofs << distances[i] << ' ' ;
00883 ofs << '\n' ;
00884 }
00885
00886 }
00887
00888
00889
00890 namespace {
00891
00892
00893 void save(const OpenCVMatrix& M, const std::string& file_name)
00894 {
00895 std::ofstream ofs(file_name.c_str()) ;
00896 for (int i = 0; i < M.num_rows(); ++i) {
00897 for (int j = 0; j < M.num_cols(); ++j)
00898 ofs << M.get<float>(i, j) << ' ' ;
00899 ofs << '\n' ;
00900 }
00901 }
00902
00903
00904
00905 void append(const Image<double>& I, const std::string& file_name,
00906 const std::string& image_name)
00907 {
00908 if (! I.initialized())
00909 throw std::runtime_error("save empty image to " + file_name + "?!?") ;
00910 if (file_name.empty())
00911 throw std::runtime_error("must specify file name for saving Image") ;
00912
00913 std::ofstream ofs(file_name.c_str(), std::ios::out | std::ios::app) ;
00914 if (! image_name.empty())
00915 ofs << image_name << ' ' ;
00916 ofs << I ;
00917 }
00918
00919
00920 Image<double>
00921 load_image(const std::string& file_name, int width, int height)
00922 {
00923 try
00924 {
00925 Image<double> I(width, height, NO_INIT) ;
00926 std::ifstream ifs(file_name.c_str()) ;
00927 ifs >> I ;
00928 return I ;
00929 }
00930 catch (std::exception&)
00931 {
00932 throw std::runtime_error(file_name + ": out of data?!?") ;
00933 }
00934 }
00935
00936
00937 std::ostream& operator<<(std::ostream& os, const Image<double>& I)
00938 {
00939 for (int y = 0; y < I.getHeight(); ++y) {
00940 for (int x = 0; x < I.getWidth(); ++x)
00941 os << I.getVal(x, y) << ' ' ;
00942 os << '\n' ;
00943 }
00944 return os ;
00945 }
00946
00947
00948
00949
00950
00951
00952 std::istream& operator>>(std::istream& is, Image<double>& I)
00953 {
00954 double d ;
00955 for (int y = 0; y < I.getHeight(); ++y)
00956 for (int x = 0; x < I.getWidth(); ++x)
00957 if (is >> d)
00958 I.setVal(x, y, d) ;
00959 else
00960 throw std::runtime_error("not enough data for Image<double>?!?") ;
00961 return is ;
00962 }
00963
00964
00965
00966
00967
00968 TrainingDB load_training_database(const std::string& file_name)
00969 {
00970 TrainingDB db ;
00971
00972 std::ifstream ifs(file_name.c_str()) ;
00973 for(;;)
00974 {
00975 try
00976 {
00977 std::istringstream line(getline(ifs)) ;
00978
00979 int segment ;
00980 GistVector G(GECB_NUM_PRINCIPAL_COMPONENTS, 1, ZEROS) ;
00981 line >> segment >> G ;
00982
00983 db.insert(std::make_pair(segment, G)) ;
00984 }
00985 catch (std::exception&)
00986 {
00987 break ;
00988 }
00989 }
00990
00991 return db ;
00992 }
00993
00994
00995 std::string getline(std::istream& is)
00996 {
00997 std::string line ;
00998 getline(is, line) ;
00999 if (! is || line.empty())
01000 throw std::runtime_error("unable to read from input stream") ;
01001 return line ;
01002 }
01003
01004 }
01005
01006
01007
01008 namespace {
01009
01010
01011
01012
01013
01014
01015 template<typename T>
01016 std::string to_string(const T& t)
01017 {
01018 std::ostringstream str ;
01019 str << t ;
01020 return str.str() ;
01021 }
01022
01023
01024 int count_lines(const std::string& file_name)
01025 {
01026 int n = -1 ;
01027 std::ifstream ifs(file_name.c_str()) ;
01028
01029 std::string dummy ;
01030 while (ifs) {
01031 getline(ifs, dummy) ;
01032 ++n ;
01033 }
01034 return n ;
01035 }
01036
01037 }
01038
01039
01040
01041
01042
01043
01044