openCVでemアルゴリズム

昨日はopenCVでのemアルゴリズム実装のみ.ほんとに初級機能しか使ってないが,今後も使うので疑問点と共にめもっておく.

openCVemアルゴリズム

emアルゴリズムは混合正規分布の各パラメータの最尤推定してくれるアルゴリ様.具体的にはデータの集合を渡せば指定した混合数だけ平均,重み,分散共分散行列が得られる.オプションで,各サンプル点がどの正規分布に含まれる可能性が高いかもラベリングしてくれる.収束性が良いと,ものの本に書いてあった.
今回はGraphCutsを用いた領域抽出において,ユーザーの手入力により得る背景/物体の代表点と各ピクセルの類似度を推定するために3変量(RGB)正規分布を求める.細かいことはリファレンス参照 http://opencv.jp/opencv-1.0.0/document/opencvref_ml_em.html
いざ実装⇒


// include

#include <ml.h>
#include <highgui.h>

ml.hを忘れずに.


// 下準備

const int N = 2;
int nsamples = 10;
CvMat* samples = cvCreateMat(nsamples,3,CV_32FC1);
CvMat* labels = cvCreateMat(nsamples,1,CV_32SC1);
CvEM em_model;
CvEMParams params;

  • Nはいくつの混合分布に当てはめるか
  • nsamplesはサンプル数
  • CvMat* samplesはサンプル集合を自力で入れる行列.(サンプル数)×(変量)となる.今回は変量はRGB値の3.
  • CvMat* labelsは,ラベリング結果を受け取るための行列.(サンプル数)×1となる.
    • 変数型は整数でないと通らない
  • CvEM em_modelは…もでるの?
  • CvEMParams paramsにはemを解くための平均や分散などの初期値情報を入れる.取り立てて無ければNULLで初期化する.詳しくはリファレンス参照.


// クラスタリング

em_model.train(samples,0,params,labels);

  • ここでアルゴリズムはつどー
  • たぶん4つ目の引数を0にすればラベリング作業は省ける.GraphCutsの場合ここでラベリングしても余計なお世話なのでしなくてよさそう.マハラノビスの距離とか見てるんだらうか.


// ☆得られた混合正規分布の各パラメータのみかた☆

params.means = em_model.get_means();
params.covs = (const CvMat**)em_model.get_covs();
params.weights = em_model.get_weights();

  • ここが一番わからんかった….よく考えたら当たり前なんだけど,まずは結果をparamsに代入する.
  • すると,means,covs,weightsにはそれぞれ平均,分散共分散行列,重みが行列の形で入ってくる.
  • あとはそれぞれcvmGetとかで中身を見ればよい.
    • なぜか平均は列ベクトル,重みは行ベクトルの形で入っている.アクセスするとき注意.


ちなみに分散共分散行列はNの数だけあるため,params.covsは行列の配列を指すポインタである.そのため変数の宣言が**covsとなってる(んだよね?).例えばm番目の正規分布の分散共分散行列のi行j列目を見たければ,

cvmGet(params.covs[m],i,j);


とすればよい.ポインタ,もっとちゃんと勉強しとけばよかった.
なお,OpenCVのリファレンスではparams.covsが共変動行列と記述されているが,変動は偏差の平方和(分散の式の分子)では…?実際に確かめてみるとサンプル数でちゃんと割った値が出てくるので,いわゆる分散共分散行列なんだとおもう.紀文…いやたぶん.



大体以上.
共変行列の値を抜き出すあたりが一番大変だった.**covs とあったら慣れてる人はすぐ配列のポインタだとわかるんだろーか….


ちなみに今後はmatlab使うかもしれんので,matlabemアルゴリズム検索してみた.…すごい簡単そうなんだけどorz
これとか.http://www.viplab.is.tsukuba.ac.jp/~hirai/GraduateSchool/index.html

まーいーさー