FrontPage | changes | index | create | search | preferences

letter_recog.cpp

Last-Modified: Mon Feb 18 15:47 2008; Revision: 1.6; by momma
edit | copy | diff | history | raw
  1. 内容
  2. 必要なデータ
  3. ソース斜め読み
    1. main
    2. read_num_class_data( const char* filename, int var_count, CvMat** data, CvMat** responses )
    3. build_rtrees_classifier( char* data_filename, char* filename_to_save, char* filename_to_load )
    4. build_boost_classifier( char* data_filename, char* filename_to_save, char* filename_to_load )
      1. メモ
    5. build_mlp_classifier( char* data_filename, char* filename_to_save, char* filename_to_load )

サンプルのletter_recog.cppについて

[edit]

内容

[edit]

必要なデータ

UCI Machine Learning Repository: Letter Recognition Data SetのData Folderからletter-recognition.dataを入手して、実行形式ファイルが出力されるフォルダに置く。

  T,2,8,3,5,1,8,13,0,6,6,10,8,0,8,0,8
  I,5,12,3,7,2,10,5,5,4,13,3,9,2,8,4,10
  D,4,11,6,8,6,10,6,2,6,10,3,7,3,7,3,9
  N,7,11,6,6,3,5,9,4,6,4,4,10,6,10,2,8
  G,2,1,3,1,1,8,6,6,6,6,5,9,1,7,5,10
  S,4,11,5,8,3,8,8,6,9,5,6,6,0,8,9,7
  B,4,2,5,4,4,8,7,6,6,7,6,6,2,8,7,10

のような並びになっている。行頭から

  1. AからZまでの大文字(従ってクラスは26通りになる)
  2. x-box horizontal position of box (integer)
  3. y-box vertical position of box (integer)
  4. width width of box (integer)
  5. high height of box (integer)
  6. onpix total # on pixels (integer)
  7. x-bar mean x of on pixels in box (integer)
  8. y-bar mean y of on pixels in box (integer)
  9. x2bar mean x variance (integer)
  10. y2bar mean y variance (integer)
  11. xybar mean x y correlation (integer)
  12. x2ybr mean of x * x * y (integer)
  13. xy2br mean of x * y * y (integer)
  14. x-ege mean edge count left to right (integer)
  15. xegvy correlation of x-ege with y (integer)
  16. y-ege mean edge count bottom to top (integer)
  17. yegvx correlation of y-ege with x (integer)

2-17が特徴量。訳は略。

[edit]

ソース斜め読み

[edit]

main

  int main( int argc, char *argv[] )
  {
      char* filename_to_save = 0;
      char* filename_to_load = 0;
      char default_data_filename[] = "./letter-recognition.data";
      char* data_filename = default_data_filename;
      int method = 0;

      int i;
      //起動時のオプションの処理
      for( i = 1; i < argc; i++ )
      {
          //-data ファイル名 でデータファイルを指定。通常は不要
          if( strcmp(argv[i],"-data") == 0 ) // flag "-data letter_recognition.xml" ←letter_recognition.dataの間違い
          {
              i++;
              data_filename = argv[i];
          }
          //-save ファイル名 で分類器の状態をxmlで保存
          else if( strcmp(argv[i],"-save") == 0 ) // flag "-save filename.xml"
          {
              i++;
              filename_to_save = argv[i];
          }
          //-load ファイル名 saveオプションで保存した分類器の呼出し
          else if( strcmp(argv[i],"-load") == 0) // flag "-load filename.xml"
          {
              i++;
              filename_to_load = argv[i];
          }
          //Boosting
          else if( strcmp(argv[i],"-boost") == 0)
          {
              method = 1;
          }
          //MLP
          else if( strcmp(argv[i],"-mlp") == 0 )
          {
              method = 2;
          }
          else
              break;
      }

      if( i < argc ||
          //各手法での学習
          (method == 0 ?
          build_rtrees_classifier( data_filename, filename_to_save, filename_to_load ) :
          method == 1 ?
          build_boost_classifier( data_filename, filename_to_save, filename_to_load ) :
          method == 2 ?
          build_mlp_classifier( data_filename, filename_to_save, filename_to_load ) :
          -1) < 0)
      {
          printf("This is letter recognition sample.\n"
                  "The usage: letter_recog [-data <path to letter-recognition.data>] \\\n"
                  "  [-save <output XML file for the classifier>] \\\n"
                  "  [-load <XML file with the pre-trained classifier>] \\\n"
                  "  [-boost|-mlp] # to use boost/mlp classifier instead of default Random Trees\n" );
      }
      return 0;
  }
[edit]

read_num_class_data( const char* filename, int var_count, ?CvMat** data, ?CvMat** responses )

filename(letter-recognition.data)からデータ数個の1次元?CvMatのresponses(正解)とvar_count個の特徴量xデータ数の2次元?CvMatのdataを作成する。

やっていることはcsvファイルの先頭をresponsesに、それ以降のvar_count個をdataに詰め込むだけなのだが、malloc等を使わずにOpenCVのAPIだけを使って仕上げているので参考になる。

[edit]

build_rtrees_classifier( char* data_filename, char* filename_to_save, char* filename_to_load )

  static
  int build_rtrees_classifier( char* data_filename,
      char* filename_to_save, char* filename_to_load )
  {
      CvMat* data = 0;
      CvMat* responses = 0;
      CvMat* var_type = 0;
      CvMat* sample_idx = 0;
  
      int ok = read_num_class_data( data_filename, 16, &data, &responses );
      int nsamples_all = 0, ntrain_samples = 0;
      int i = 0;
      double train_hr = 0, test_hr = 0;
      CvRTrees forest; //Random Treesのクラス
      CvMat* var_importance = 0;
  
      if( !ok )
      {
          printf( "Could not read the database %s\n", data_filename );
          return -1;
      }
  
      printf( "The database %s is loaded.\n", data_filename );
      //サンプル数はCvMatのrows(行数)から取得
      nsamples_all = data->rows;
      //全体の8割を学習に使用
      ntrain_samples = (int)(nsamples_all*0.8);

      // Create or load Random Trees classifier
      if( filename_to_load ) //-loadで分類器の状態のファイルが指定された場合
      {
          // load classifier from the specified file
          forest.load( filename_to_load ); //状態のロード。OpenCVの機械学習での共通のメソッド
          ntrain_samples = 0;
          if( forest.get_tree_count() == 0 ) //Random Treesのものでないとtree_countが0になるらしい
          {
              printf( "Could not read the classifier %s\n", filename_to_load );
              return -1;
          }
          printf( "The classifier %s is loaded.\n", data_filename );
      }
      else
      {//新たに作成する場合
          // create classifier by using <data> and <responses>
          printf( "Training the classifier ...");

          // 1. create type mask
          //dataおよびresponsesの形式の指定
          //特徴量の数(CvMatのcols(列数から取得)+1(出力でもあるresponsesの分)の形式を指定する
          //CV_VAR_NUMERICAL:数値
          //CV_VAR_ORDERD:連続量
          //CV_VAR_CATEGORICAL:質的データ
          var_type = cvCreateMat( data->cols + 1, 1, CV_8U );
          cvSet( var_type, cvScalarAll(CV_VAR_ORDERED) );
          //最後の1つ(出力でもあるresponsesの形式)を質的データに指定
          cvSetReal1D( var_type, data->cols, CV_VAR_CATEGORICAL );

          // 2. create sample_idx
          //sample_idx(どのサンプルを使うかのインデックス)の作成
          //1行nsamples_all列のCvMatを作成。これが1なら該当する番目のデータを参照(学習に使う)、0なら無視
          sample_idx = cvCreateMat( 1, nsamples_all, CV_8UC1 );
          {
              CvMat mat;
              //0番目からntrain_samples-1番目までののCvMatを参照(第4引数の場所は含まれない点に注意)
              cvGetCols( sample_idx, &mat, 0, ntrain_samples );
              //参照したCvMatに1を代入
              cvSet( &mat, cvRealScalar(1) );
              //ntrain_samples番目からnsamples_all-1番目までのCvMatを参照
              cvGetCols( sample_idx, &mat, ntrain_samples, nsamples_all );
              //0を代入
              cvSetZero( &mat );
          }

          // 3. train classifier
          //分類器の学習
          //http://opencv.jp/opencv/document/opencvref_ml_introduction.html#decl_CvStatModel_train
          //を参照
          //パラメータについては
          //http://opencv.jp/opencv/document/opencvref_ml_randomtree.html#decl_CvRTParams
          //http://opencv.jp/opencv/document/opencvref_ml_dtree.html#decl_CvDTreeParams
          //を参照
          forest.train( data, CV_ROW_SAMPLE, responses, 0, sample_idx, var_type, 0,
              CvRTParams(10,10,0,false,15,0,true,4,100,0.01f,CV_TERMCRIT_ITER));
          printf( "\n");
      }

      // compute prediction error on train and test data
      //trainおよびtestデータを用いた予測を行ない、学習の誤差を求める
      for( i = 0; i < nsamples_all; i++ )
      {
          double r;
          CvMat sample;
          //データを1つずつ取得して検証する
          cvGetRow( data, &sample, i );
          //http://opencv.jp/opencv/document/opencvref_ml_randomtree.html#decl_CvRTrees_predict
          //を参照
          r = forest.predict( &sample );
          //data.fl[i]はi番目のデータをfloatで取得するの意
          //FLT_EPSILONはfloatの場合の丸め誤差の最大値。要するに差が無い場合は絶対値がこれ以下になる
          //#define FLT_EPSILON     1.192092896e-07F        /* smallest such that 1.0+FLT_EPSILON != 1.0 */
          r = fabs((double)r - responses->data.fl[i]) <= FLT_EPSILON ? 1 : 0;
          //trainかtestか判別して正解数を記録
          if( i < ntrain_samples )
              train_hr += r;
          else
              test_hr += r;
      }
      //正解率を求める
      test_hr /= (double)(nsamples_all-ntrain_samples);
      train_hr /= (double)ntrain_samples;
      //百分率で表示
      printf( "Recognition rate: train = %.1f%%, test = %.1f%%\n",
              train_hr*100., test_hr*100. );
      //get_tree_countメソッドはntreesを返す
      printf( "Number of trees: %d\n", forest.get_tree_count() );

      // Print variable importance
      //get_var_importanceメソッドはCvMat型のvar_importance(変数の重要度)を返す
      var_importance = (CvMat*)forest.get_var_importance();
      if( var_importance )
      {
          //重要度の合計で各変数の重要度を割り、貢献している率(百分率)を示す
          double rt_imp_sum = cvSum( var_importance ).val[0];
          printf("var#\timportance (in %%):\n");
          for( i = 0; i < var_importance->cols; i++ )
              printf( "%-2d\t%-4.1f\n", i,
              100.f*var_importance->data.fl[i]/rt_imp_sum);
      }

      //Print some proximitites
      //letter-recognition.dataの0、103、106番目の'T'についてノード間での近さを求める
      printf( "Proximities between some samples corresponding to the letter 'T':\n" );
      {
          CvMat sample1, sample2;
          const int pairs[][2] = {{0,103}, {0,106}, {106,103}, {-1,-1}};

          for( i = 0; pairs[i][0] >= 0; i++ )
          {
              cvGetRow( data, &sample1, pairs[i][0] );
              cvGetRow( data, &sample2, pairs[i][1] );
              printf( "proximity(%d,%d) = %.1f%%\n", pairs[i][0], pairs[i][1],
                  forest.get_proximity( &sample1, &sample2 )*100. );
          }
      }

      // Save Random Trees classifier to file if needed
      //-saveオプションで保存先が指定されている場合
      if( filename_to_save )
          forest.save( filename_to_save );

      cvReleaseMat( &sample_idx );
      cvReleaseMat( &var_type );
      cvReleaseMat( &data );
      cvReleaseMat( &responses );

      return 0;
  }
[edit]

build_boost_classifier( char* data_filename, char* filename_to_save, char* filename_to_load )

OpenCVにおけるBoosted treeは2クラスの分類までしか対応していないので、Unrollingして2クラス分類に変換している。

具体的にはデータ群(1サンプルあたり16個入り)dataとクラス(26通り)responsesについて、 train用全サンプルをクラスの数だけ複製し、各サンプルのケツに0-25の値をインデックスとして付与したものをnew_dataとし、 そのインデックスとresponsesが一致した場合を1とするnew_responsesを作成している。

サンプルdataresponses
サンプルその1データ群その119('T'は20番目)

だった場合、

サンプルnew_datanew_responses
サンプルその1データ群その1, 00
サンプルその1データ群その1, 10
省略
サンプルその1データ群その1, 191
省略
サンプルその1データ群その1, 250

となる。これをtrain用全サンプルに対して行なっている。

ちなみにvar_typeはインデックスとnew_responsesについては

   cvSetReal1D( var_type, var_count, CV_VAR_CATEGORICAL );
   cvSetReal1D( var_type, var_count+1, CV_VAR_CATEGORICAL );

として質的データの扱いにしている。

?CvBoost::trainについてはCvBoost::trainのリファレンスCvBoostParamsのリファレンスおよびCvDTreeParamsのリファレンスを参照。

メモ

  static
  int build_boost_classifier( char* data_filename,
      char* filename_to_save, char* filename_to_load )
  {
      const int class_count = 26;
      CvMat* data = 0;
      CvMat* responses = 0;
      CvMat* var_type = 0;
      CvMat* temp_sample = 0;
      CvMat* weak_responses = 0;

      int ok = read_num_class_data( data_filename, 16, &data, &responses );
      int nsamples_all = 0, ntrain_samples = 0;
      int var_count;
      int i, j, k;
      double train_hr = 0, test_hr = 0;
      CvBoost boost;

      if( !ok )
      {
          printf( "Could not read the database %s\n", data_filename );
          return -1;
      }

      printf( "The database %s is loaded.\n", data_filename );
      nsamples_all = data->rows;
      ntrain_samples = (int)(nsamples_all*0.5);
      var_count = data->cols;

      // Create or load Boosted Tree classifier
      if( filename_to_load )
      {
          // load classifier from the specified file
          boost.load( filename_to_load );
          ntrain_samples = 0;
          if( !boost.get_weak_predictors() )
          {
              printf( "Could not read the classifier %s\n", filename_to_load );
              return -1;
          }
          printf( "The classifier %s is loaded.\n", data_filename );
      }
      else
      {
          // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
          //
          // As currently boosted tree classifier in MLL can only be trained
          // for 2-class problems, we transform the training database by
          // "unrolling" each training sample as many times as the number of
          // classes (26) that we have.
          //
          // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        //unrollingの説明
        //unrolling後のデータnew_data、応答new_responses用のCvMat
        //new_dataはインデックスが加わるのでvar_count+1個分入れ物を作る

          CvMat* new_data = cvCreateMat( ntrain_samples*class_count, var_count + 1, CV_32F );
          CvMat* new_responses = cvCreateMat( ntrain_samples*class_count, 1, CV_32S );

          // 1. unroll the database type mask
          printf( "Unrolling the database...\n");
        //train用データのunrolling
          for( i = 0; i < ntrain_samples; i++ )
          {
              //dataから1サンプル分のポインタの取得
              float* data_row = (float*)(data->data.ptr + data->step*i);
              //クラス数(26)分のループ
              for( j = 0; j < class_count; j++ )
              {
                  //new_dataの1サンプル、1クラス分のポインタ取得
                  float* new_data_row = (float*)(new_data->data.ptr +
                                  new_data->step*(i*class_count+j));
                  //特徴量のコピー
                  for( k = 0; k < var_count; k++ )
                      new_data_row[k] = data_row[k];
                  //インデックスの埋込み
                  new_data_row[var_count] = (float)j;
                  //インデックスとresponsesの内容が等しければ1をnew_responsesに入れる。不等なら0
                  new_responses->data.i[i*class_count + j] = responses->data.fl[i] == j+'A';
              }
          }

          // 2. create type mask
          //type maskの作成
          //var_countよりインデックスとnew_responsesの2個分多い
          var_type = cvCreateMat( var_count + 2, 1, CV_8U );
          //CV_VAR_ORDERD(量的データ)で全部埋める
          cvSet( var_type, cvScalarAll(CV_VAR_ORDERED) );
          // the last indicator variable, as well
          // as the new (binary) response are categorical
          //インデックスとバイナリ(01)のnew_responsesは質的データ(CV_VAR_CATEGORICAL)
          cvSetReal1D( var_type, var_count, CV_VAR_CATEGORICAL );
          cvSetReal1D( var_type, var_count+1, CV_VAR_CATEGORICAL );

          // 3. train classifier
          printf( "Training the classifier (may take a few minutes)...");
          boost.train( new_data, CV_ROW_SAMPLE, new_responses, 0, 0, var_type, 0,
              CvBoostParams(CvBoost::REAL, 100, 0.95, 5, false, 0 ));
          cvReleaseMat( &new_data );
          cvReleaseMat( &new_responses );
          printf("\n");
      }
      //テスト用サンプルの入れ物
      temp_sample = cvCreateMat( 1, var_count + 1, CV_32F );
      //弱い分類器の出力の入れ物
      weak_responses = cvCreateMat( 1, boost.get_weak_predictors()->total, CV_32F ); 

      // compute prediction error on train and test data
      for( i = 0; i < nsamples_all; i++ )
      {
          int best_class = 0;
          double max_sum = -DBL_MAX;
          double r;
          CvMat sample;
          //1サンプル分のdataを取得
          cvGetRow( data, &sample, i );
          //temp_sampleにsampleをコピー
          for( k = 0; k < var_count; k++ )
              temp_sample->data.fl[k] = sample.data.fl[k];

          for( j = 0; j < class_count; j++ )
          {
              //インデックスだけ0~25に変えてテスト
              temp_sample->data.fl[var_count] = (float)j;
              boost.predict( temp_sample, 0, weak_responses );
              double sum = cvSum( weak_responses ).val[0];
              //最もweak_responsesの総和が大きい
              //(間違った答えはだいたい大きな負数になる)ベストなクラスを探す
              if( max_sum < sum )
              {
                  max_sum = sum;
                  best_class = j + 'A';
              }
          }
          //best_classとresponsesが等しいか?
          r = fabs(best_class - responses->data.fl[i]) < FLT_EPSILON ? 1 : 0;
          //test,trainデータに対する正解数の総和を求める
          if( i < ntrain_samples )
              train_hr += r;
          else
              test_hr += r;
      }

      test_hr /= (double)(nsamples_all-ntrain_samples);
      train_hr /= (double)ntrain_samples;
      printf( "Recognition rate: train = %.1f%%, test = %.1f%%\n",
              train_hr*100., test_hr*100. );

      printf( "Number of trees: %d\n", boost.get_weak_predictors()->total );

      // Save classifier to file if needed
      if( filename_to_save )
          boost.save( filename_to_save );

      cvReleaseMat( &temp_sample );
      cvReleaseMat( &weak_responses );
      cvReleaseMat( &var_type );
      cvReleaseMat( &data );
      cvReleaseMat( &responses );

      return 0;
  }
[edit]

build_mlp_classifier( char* data_filename, char* filename_to_save, char* filename_to_load )

OpenCVのMLPは質的データに対応していないのでresponsesをクラス全てに対するビット列に置き換えている点に注意。

  static
  int build_mlp_classifier( char* data_filename,
      char* filename_to_save, char* filename_to_load )
  {
      const int class_count = 26;
      CvMat* data = 0;
      CvMat train_data;
      CvMat* responses = 0;
      CvMat* mlp_response = 0;

      int ok = read_num_class_data( data_filename, 16, &data, &responses );
      int nsamples_all = 0, ntrain_samples = 0;
      int i, j;
      double train_hr = 0, test_hr = 0;
      CvANN_MLP mlp;

      if( !ok )
      {
          printf( "Could not read the database %s\n", data_filename );
          return -1;
      }

      printf( "The database %s is loaded.\n", data_filename );
      nsamples_all = data->rows;
      ntrain_samples = (int)(nsamples_all*0.8);

      // Create or load MLP classifier
      if( filename_to_load )
      {
          // load classifier from the specified file
          mlp.load( filename_to_load );
          ntrain_samples = 0;
          if( !mlp.get_layer_count() )
          {
              printf( "Could not read the classifier %s\n", filename_to_load );
              return -1;
          }
          printf( "The classifier %s is loaded.\n", data_filename );
      }
      else
      {
          // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
          //
          // MLP does not support categorical variables by explicitly.
          // So, instead of the output class label, we will use
          // a binary vector of <class_count> components for training and,
          // therefore, MLP will give us a vector of "probabilities" at the
          // prediction stage
          //
          // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
          //MLPは質的データの出力には対応していないので
          //new_responsesはバイナリ(01)のベクトルとする
          //このベクトルはクラス数分の大きさを持ち、理想的には正解のクラスにのみ1が立つ
          //(実際のpredictの結果は1になる事は殆どなく、0~1の範囲で尤もらしさを示すことになる)
          
          //学習用のサンプル分作るので、大きさはntrain_samples×class_countになる
          CvMat* new_responses = cvCreateMat( ntrain_samples, class_count, CV_32F );

          // 1. unroll the responses
          printf( "Unrolling the responses...\n");
          for( i = 0; i < ntrain_samples; i++ )
          {
              //responsesをAを0とする整数に変換
              int cls_label = cvRound(responses->data.fl[i]) - 'A';
              //new_responsesの1サンプル分のベクトルのポインタの取得
              float* bit_vec = (float*)(new_responses->data.ptr + i*new_responses->step);
              //全部に0(float)を埋込む
              for( j = 0; j < class_count; j++ )
                  bit_vec[j] = 0.f;
              //cls_label(正解)にだけ1(float)を立てる
              bit_vec[cls_label] = 1.f;
          }
          //train_dataにdataの0~ntrain_samples-1サンプルまで取得
          cvGetRows( data, &train_data, 0, ntrain_samples );

          // 2. train classifier
          //入力層:特徴量の数
          //隠れ層1:100
          //隠れ層2:100
          //出力層:26(さっき作ったバイナリベクタの数)
          int layer_sz[] = { data->cols, 100, 100, class_count };
          //(int)(sizeof(layer_sz)/sizeof(layer_sz[0]))は要するに入れ物が何個かという計算
          //ここでは1×4のCvMatを作り、中にlayer_szを入れている
          CvMat layer_sizes =
              cvMat( 1, (int)(sizeof(layer_sz)/sizeof(layer_sz[0])), CV_32S, layer_sz );
          //CvANN_MLP::createについては
          //http://opencv.jp/opencv/document/opencvref_ml_nn.html#decl_CvANN_MLP_create 参照
          mlp.create( &layer_sizes );
          printf( "Training the classifier (may take a few minutes)...");
          //CvANN_MLP::trainについては
          //http://opencv.jp/opencv/document/opencvref_ml_nn.html#decl_CvANN_MLP_train
          //http://opencv.jp/opencv/document/opencvref_ml_nn.html#decl_CvANN_MLP_TrainParams
          //http://opencv.jp/opencv/document/opencvref_cxcore_basic.html#decl_CvTermCriteria
          //を参照
          mlp.train( &train_data, new_responses, 0, 0,
              CvANN_MLP_TrainParams(cvTermCriteria(CV_TERMCRIT_ITER,300,0.01),
              CvANN_MLP_TrainParams::RPROP,0.01));
          cvReleaseMat( &new_responses );
          printf("\n");
      }
      //応答の入れ物
      mlp_response = cvCreateMat( 1, class_count, CV_32F );

      // compute prediction error on train and test data
      //trainとtestの両サンプルについてpredictする
      for( i = 0; i < nsamples_all; i++ )
      {
          int best_class;
          CvMat sample;
          //dataから1サンプル取得
          cvGetRow( data, &sample, i );
          CvPoint max_loc = {0,0};
          //predictメソッドは
          //virtual float predict( const CvMat* _inputs, CvMat* _outputs ) const;
          //と宣言されている
          mlp.predict( &sample, mlp_response );
          //cvMinMaxLocで最大となった位置(何番目の文字を正解(より1に近い出力)としたか)を探す
          //CVAPI(void)  cvMinMaxLoc( const CvArr* arr, double* min_val, double* max_val,
          //                CvPoint* min_loc CV_DEFAULT(NULL),
          //                CvPoint* max_loc CV_DEFAULT(NULL),
          //                const CvArr* mask CV_DEFAULT(NULL) );
          //cvMinMaxLocはarrの最小値min_val、最大値max_val
          //最小となった位置min_loc、最大となった位置max_locのポインタを返す。
          //不要な項目についてはNULLを渡しておけば良い
          //という訳でmax_loc.xにはどこが一番確からしいかの位置を指す
          //当たり前だがmax_loc.yは0(1行目)
          cvMinMaxLoc( mlp_response, 0, 0, 0, &max_loc, 0 );
          //ASCIIコードに変換
          best_class = max_loc.x + 'A';
          //responsesとbest_classが一致すれば1。外れれば0
          int r = fabs((double)best_class - responses->data.fl[i]) < FLT_EPSILON ? 1 : 0;
          //train,testの正解数に加算
          if( i < ntrain_samples )
              train_hr += r;
          else
              test_hr += r;
      }

      test_hr /= (double)(nsamples_all-ntrain_samples);
      train_hr /= (double)ntrain_samples;
      printf( "Recognition rate: train = %.1f%%, test = %.1f%%\n",
              train_hr*100., test_hr*100. );

      // Save classifier to file if needed
      if( filename_to_save )
          mlp.save( filename_to_save );

      cvReleaseMat( &mlp_response );
      cvReleaseMat( &data );
      cvReleaseMat( &responses );

      return 0;
  }
[edit]

Powered by WiKicker

日本大学理工学部へ 電気工学科へ 計測工学研究室へ