パーティクルフィルタ
本物のページはこちら→particle-filter
Included page "particle-filter" does not exist (create it now)
パーティクルフィルタとは?
画像の中で物体を追従するのにつかう。
アルゴリズムをおおざっぱに説明すると、
画像の中のある特定の小さな四角い領域を決めて
そこを基準に、ランダムに点(パーティクル)を置く。
そのランダムに置いた点を基準に更に、四角い領域の画素値を調べて、探したい画像をどのくらい類似しているのかを計算する。(いわゆる、類似度の計算というやつ)
各パーティクルの類似度を重みとして、次に置く四角形を決める。
この、四角形で、物体を追従することになる。
というかんじ。
類似度の計算
画像をグレースケールにしてヒストグラムを計算して比較するのが一般的。
私的にはなんでRGBまるごと計算しないんだって思うけど、
速度的な問題なのだと思う。
当時OpenCVが難しいと思っていた私は以下のようなハードコードを書いた。
void GetHistgram(CPoint& _pt, float* _histgram) { memset(_histgram,0,256); for(int y=-TESTAREA;y<TESTAREA;y++){ for(int x=-TESTAREA;x<TESTAREA;x++){ int luminance=mTextureDataPointer[(TEXY-(_pt.y+y)-1)*TEXY+(_pt.x+x)];//ここでエラー _histgram[luminance]+=1.0f; } } //ヒストグラムが足して1になるよう正規化する。 float maxvalue=0;//0より小さい値はないはず。 for(int i=0;i<256;i++){ if(maxvalue < _histgram[i]){ maxvalue=_histgram[i]; } } for(int i=0;i<256;i++){ _histgram[i]/=maxvalue; } }
- TESTAREA
- 小さい四角形の領域
- mTextureDataPointer
- 画像データ
- CPoint
- パーティクルの座標
ヒストグラムから類似度を算出する
比べたい画像のヒストグラム同士をかけ算して、その結果を積算していくのが一般的。
数式で書くとこうである。
\begin{align} S=\sum^{n}_{i=0} H(i) \end{align}
- S
- 類似度 similarity
- H(i)
- 輝度iがその画像で出現した回数 ヒストグラム関数
int CalcSimilarity(float* _srcHistgram){ mSimilarity=0; for(int i=THRESHOLD;i<256;i++){ mSimilarity+=(mHistgram[i]*_srcHistgram[i]); } return mSimilarity; }
パーティクルの配置
void COpenGLControl::RefineParticles(void)//平均値以下の粒子を捨て、新しい粒子を入れる { mSimilarityAverage=(mSimilaritySam/(float)PARTICLENUM)/mSimilaritySam; std::sort(mParticles.begin(),mParticles.end()); srand( GetTickCount( ) ); for(int i=PARTICLENUM/8;i<PARTICLENUM;i++){ //if(mParticles[i].mSimilarity<mSimilarityAverage){//平均値以上のものは保存し、平均値以下のものは消して //新しいターゲットを中心としたランダム位置の粒子にする float a=rand()/(float)RAND_MAX;//0〜RAND_MAX RAND_MAXはコンパイラによって違う。 float b=rand()/(float)RAND_MAX; mParticles[i].mPt.x=mTarget.mPt.x+(int)((float)TESTAREA*2*sqrt(-2.0*log(a))*cos(2.0*M_PI*b)); mParticles[i].mPt.y=mTarget.mPt.y+(int)((float)TESTAREA*2*sqrt(-2.0*log(a))*sin(2.0*M_PI*b)); if(mParticles[i].mPt.y<0 || mParticles[i].mPt.x<0){assert(!"0以下な数字!!");} //} } } void COpenGLControl::CalcSimilarity(void) { float maximum=-FLT_MAX; float minimum=FLT_MAX; maxindex=0; minindex=0; mSimilaritySam=0;//類似度の合計値(あとで正規化するのに使用する) mSimilarityAverage;//類似度の平均値(あとで平均値以下を切り捨てるのに使う) //ランダムに散らした後、各点を中心にした8×8エリアのヒストグラムを取る。 //ヒストグラムを利用した類似度 for(int i=0;i<PARTICLENUM;i++){ // mParticles[i].GenerateRects(); // SavePartOfBitmap(mParticles[i].mRect,mParticles[i].mBitmap);// GetHistgram(mParticles[i].mPt,mParticles[i].mHistgram); mParticles[i].CalcSimilarity(mTarget.mHistgram/*,mTarget.mBitmap*/);//類似度の計算 if(maximum<mParticles[i].mSimilarity){ maximum=mParticles[i].mSimilarity; maxindex=i; } if(minimum>mParticles[i].mSimilarity){ minimum=mParticles[i].mSimilarity; minindex=i; } mSimilaritySam+=mParticles[i].mSimilarity; } mTopParticle.mPt.x=mParticles[maxindex].mPt.x;//黄色 mTopParticle.mPt.y=mParticles[maxindex].mPt.y; mBottomParticle.mPt.x=mParticles[minindex].mPt.x;//水色 mBottomParticle.mPt.y=mParticles[minindex].mPt.y; mTopParticle.Refresh(mParticles[maxindex].mPt.x,mParticles[maxindex].mPt.y); mBottomParticle.Refresh(mParticles[minindex].mPt.x,mParticles[minindex].mPt.y); }