OpenCVでSVMを使った機械学習&推定
OpenCVは本当に便利ですね.
さまざまなツールが内包されていますが,その中でも機械学習に関する部分をいじってみようと思い,SVMに手をつけました.
やっていることはサンプルコードの域を脱していませんが,自分で書いてみることで使い方がわかってきました.
テーマは,「ぼけた画像(ピントが合っていない)とそうでない画像を自動的に区別する」です.
ためしに作ってみたものは性能的にイマイチでしたが,一応使い方をまとめておきます.
作ったもの
以下の機能をもつプログラムです.
・データセット(特徴量,ぼけているかどうかの判定)を読み込んで,ぼけているかどうかの判定基準を学習する
・学習した判定基準にしたがい,新たに読み込んだ特長量から画像のぼけ判定をする
ここにコミットしました.
https://github.com/glass5er/opencv-ml-svm
画像も載せたいですが,著作権的なことに触れるとまずいので,データセットだけコミットしました.
プログラムの流れ
学習フェイズ
まず,データセットを読み込みます.
最終的にsvmに渡せれば何でも良いですので,CSVファイルから読み出す形にしました.
必要なのは以下です.
- 判定フラグ(整数値)
- 特徴量データ(実数)
データの個数に決まりはありませんが,学習シナリオごとに個数が異なるのはNGです.
// training data buffer // std::vector< int > flagset; std::vector< std::vector<double> > dataset; read_csv(fname_train.c_str(), flagset, dataset); const int lines_tr = dataset.size(); const int segments = dataset[0].size(); <|| 読み出したデータを行列に格納し,学習します. train一発で学習できるのは便利です. >|cpp| // dataset -> matrix // cv::Mat flagmat(lines_tr, 1, CV_32SC1); cv::Mat datamat(lines_tr, segments, CV_32FC1); for(int i=0; i<lines_tr; i++) { flagmat.at<int>(i,0) = flagset[i]; for(int j=0; j<segments; j++) { datamat.at<float>(i,j) = dataset[i][j]; } } // training (SVM) // CvSVM svm; svm.train(datamat, flagmat);
推定フェイズ
学習のときと同じように,CSVからデータを読み込んでいます.
当然ながら,特徴量の個数は学習時と同じでないといけません.
// prediction data buffer // std::vector< int > flag_tmp; std::vector< std::vector<double> > data_tmp; read_csv(fname_pred.c_str(), flag_tmp, data_tmp); const int samples = data_tmp.size(); // each sample -> predict // cv::Mat sample(1, segments, CV_32FC1); for(int i=0; i<samples; i++) { for(int j=0; j<segments; j++) { sample.at<float>(0,j) = data_tmp[i][j]; } // prediction (SVM) // float res = svm.predict(sample); cout << "pred result[" << i << "] = " << res << endl; }
準備した特徴量
以下のように,画像の書く画素について周辺1画素,あるいは2画素内での
差分絶対値の最小値をとり,そのヒストグラムを特徴量としました.
(こんなので判別できるなら機械学習いらないでしょうけど,お試しということで.)
推定結果
学習シナリオ192個(ぼけているx96個,ぼけていないx96個)を使い,学習した基準に対し,
自身が正しく判定されるかを確かめました.
つまり,学習と同じデータを推定にも使ってみました.
その結果,
- ぼけている画像 : 正解80/96, 不正解16/96
- ぼけていない画像 : 正解76/96, 不正解20/96
という,あまりよろしくない識別率が出ました.
特徴量しだいでどうにでもなる部分だと思うので,再考してみようと思います.