OpenCV k近傍法 - eiichiromomma/CVMLAB GitHub Wiki
(OpenCV) k近傍法
k近傍法(あるいはk最短近傍分類: k-nearest neighbour classifer)もletter_recog.cppに加えてみた
SupportVectorMachineを参照。 オプションをくっつけるだけ。
データによっては特徴量ごとに尺度が明らかに異なる場合もあるので要注意。
そこらへんはRのMASSパッケージの原本である"S-PLUS による統計解析"の第11章あたりに話が出ている。
RTreesのを元に作ってみた。 パラメータが少ない。というかチューニングのしようがない。
static
int build_knearest_classifier( char* data_filename,
char* filename_to_save, char* filename_to_load )
{
CvMat* data = 0;
CvMat* responses = 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;
CvKNearest knn;
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 );
nsamples_all = data->rows;
//半分を学習に使用
ntrain_samples = (int)(nsamples_all*0.5);
// Create or load Random Trees classifier
if( filename_to_load )
{
// load classifier from the specified file
knn.load( filename_to_load );
ntrain_samples = 0;
//KNNかのチェック(未確認)
if( knn.get_var_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 ...");
// 2. create sample_idx
sample_idx = cvCreateMat( 1, nsamples_all, CV_8UC1 );
{
CvMat mat;
cvGetCols( sample_idx, &mat, 0, ntrain_samples );
cvSet( &mat, cvRealScalar(1) );
cvGetCols( sample_idx, &mat, ntrain_samples, nsamples_all );
cvSetZero( &mat );
}
// 3. train classifier
//32個までfind_nearest()の際に問合せ可能とする
//パラメータは
//http://opencv.jp/document/opencvref_ml.html#decl_CvKNearest_train
//を参照
//responsesはカテゴリ変数としている
knn.train(data,responses,sample_idx,false, 32, false);
printf( "\n");
}
// compute prediction error on train and test data
for( i = 0; i < nsamples_all; i++ )
{
double r;
CvMat sample;
cvGetRow( data, &sample, i );
//テストを行なう
//返り値は近い10個(ここでは10:さっきの32より小さければ良い)で投票を行なった結果
//近傍のベクトルの座標や距離が欲しい場合はCvMatサンプル数x個数のサイズで受け取る。詳細は
//http://opencv.jp/document/opencvref_ml.html#decl_CvKNearest_find_nearest
//を参照
r = knn.find_nearest( &sample, 10);
//結果の比較
printf("predict: %c, responses: %c, %s\n", (unsigned char)r, (unsigned char)responses->data.fl[i],
fabs((double)r - responses->data.fl[i]) <= FLT_EPSILON?"Good!":"Bad!");
r = fabs((double)r - responses->data.fl[i]) <= FLT_EPSILON ? 1 : 0;
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 KNN classifier to file if needed
if( filename_to_save )
knn.save( filename_to_save );
cvReleaseMat( &sample_idx );
cvReleaseMat( &data );
cvReleaseMat( &responses );
return 0;
}