複数の選択領域の全体的なモーション方向を求めます.
パラメタ: |
|
---|
この関数は,選択領域における全体的なモーション方向を求め,0から360度の間の角度を返します.これはまず,方向ヒストグラムを作成し,ヒストグラムが最大値を取る方向を基本方向とします.次に,全方向ベクトル(相対角度)の重み付き和を求め,基本方向からのズレを計算します:最近の動作ベクトルであるほど,より大きな重みを持ちます.結果として得られる角度は,基本方向とこのズレ量の和になります.
モーション履歴画像の勾配方向を求めます.
パラメタ: |
|
---|
この関数は, mhi の微分 と を求め,勾配方向を次のように計算します:
ここでは,(関数 CartToPolar と同様に) と の両方の符号が考慮されます.その後,勾配方向が有効である箇所を示すために mask が埋められます.
この関数は,各ピクセル の近傍において,最小( ) と最大( )の mhi 値を求め,以下の条件を満たす場合のみ有効な勾配であるとします.
ブロックマッチング法を用いて,2つの画像に対するオプティカルフローを求めます.
パラメタ: |
|
---|
この関数は,重なり合った ピクセルのブロック毎にオプティカルフローを計算します.したがって,速度場のサイズは元の画像よりも小さくなります.この関数は, prev の各ブロックに対して, curr からそれに似たブロックを探そうとします.その探索範囲は,元のブロックの近傍,あるいは,( use_previous=1 の場合)前回の関数呼び出しで計算された速度分 (velx(x0,y0),vely(x0,y0)) だけ移動したブロックの近傍です.
2つの画像に対するオプティカルフローを求めます.
パラメタ: |
|
---|
この関数は,Horn-Schunck のアルゴリズム Horn81 を用いて,1番目の画像の各ピクセルに対するフローを計算します.
2つの画像に対するオプティカルフローを求めます.
パラメタ: |
|
---|
この関数は,Lucas-Kanade のアルゴリズム Lucas81 を用いて,1番目の画像の各ピクセルに対するフローを計算します.
Lucas-Kanade法を画像ピラミッドを利用して反復実行することにより,疎な特徴集合に対するオプティカルフローを求めます.
パラメタ: |
|
---|
この関数は,Lucas-Kanade法を利用したオプティカルフロー計算を,画像ピラミッドを利用して数回反復するバージョンの実装です Bouguet00 .以前のビデオフレームの特徴点座標が与えられると,現在のフレームでの座標が計算されます.また,この関数は,サブピクセル精度で座標を検出します.
パラメータ prevPyr と currPyr は,どちらも以下の規則に従います:画像ポインタが0の場合,この関数は内部にバッファを確保後,画像ピラミッドを計算します.そして,処理が終わるとそのバッファは解放されます.画像ポインタが0ではない場合,画像ピラミッドを計算し,指定のバッファにそれを格納します.ただし,フラグ CV_LKFLOWPyr_A[B]_READY が指定されている場合を除きます.また,これらの画像は,ガウシアンピラミッドのデータが入るのに十分な大きさが必要です.関数呼び出し後,両方の画像ピラミッドが計算され,次の関数呼び出しに備えて対応画像の準備完了フラグがセットされます(つまり,通常は,一番最初の関数呼び出し以外は, CV_LKFLOWPyr_A_READY が指定されています).
物体の中心,サイズ,姿勢を求めます.
パラメタ: |
|
---|
この関数は,CAMSHIFT 物体追跡アルゴリズム Bradski98 の実装です.まず, MeanShift を用いて物体中心を求め,次に,物体のサイズと姿勢を計算します.この関数は, MeanShift 内における反復数を返します.
cv.hpp で宣言されている CamShiftTracker クラスは,この関数を利用したカラー物体追跡器の実装です.
ConDenstation の状態構造体.
typedef struct CvConDensation
{
int MP; // 観測ベクトルの次元数
int DP; // 状態ベクトルの次元数
float* DynamMatr; // 線形動力学モデル
float* State; // 状態ベクトル
int SamplesNum; // サンプル数
float** flSamples; // サンプルベクトルの配列
float** flNewSamples; // サンプルベクトルのテンポラリ配列
float* flConfidence; // 各サンプルの確からしさ
float* flCumulative; // 確からしさの累積値
float* Temp; // テンポラリベクトル
float* RandomSample; // サンプル集合を更新するためのランダムベクトル
CvRandState* RandS; // ランダムベクトルを生成するための構造体の配列
} CvConDensation;
構造体 CvConDensation は,CONditional DENSity propagATION 追跡器の状態を保存します.なお,このアルゴリズムに関する情報は, http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/ISARD1/condensation.html で知ることができます.
ConDensationフィルタ構造体の領域を確保します.
パラメタ: |
|
---|
この関数は,構造体 CvConDensation を作成し,その構造体へのポインタを返します.
ConDensation アルゴリズムのためのサンプル集合を初期化します.
パラメタ: |
|
---|
この関数は,構造体 condens 内のサンプル配列を,指定範囲内の値で埋めます.
カルマンフィルタの状態構造体.
typedef struct CvKalman
{
int MP; /* 観測ベクトルの次元数 */
int DP; /* 状態ベクトルの次元数 */
int CP; /* 制御ベクトルの次元数 */
/* 後方互換性のためのフィールド */
#if 1
float* PosterState; /* =state_pre->data.fl */
float* PriorState; /* =state_post->data.fl */
float* DynamMatr; /* =transition_matrix->data.fl */
float* MeasurementMatr; /* =measurement_matrix->data.fl */
float* MNCovariance; /* =measurement_noise_cov->data.fl */
float* PNCovariance; /* =process_noise_cov->data.fl */
float* KalmGainMatr; /* =gain->data.fl */
float* PriorErrorCovariance;/* =error_cov_pre->data.fl */
float* PosterErrorCovariance;/* =error_cov_post->data.fl */
float* Temp1; /* temp1->data.fl */
float* Temp2; /* temp2->data.fl */
#endif
CvMat* state_pre; /* 状態の推定値 (x'(k)):
x(k)=A*x(k-1)+B*u(k) */
CvMat* state_post; /* 更新された状態の推定値 (x(k)):
x(k)=x'(k)+K(k)*(z(k)-H*x'(k)) */
CvMat* transition_matrix; /* システムの時間遷移に関する線形モデル (A) */
CvMat* control_matrix; /* 制御行列 (B)
(制御していない場合は,これは利用されません) */
CvMat* measurement_matrix; /* 観測行列 (H) */
CvMat* process_noise_cov; /* プロセスノイズ(時間遷移に関するノイズ)の共分散行列 (Q) */
CvMat* measurement_noise_cov; /* 観測ノイズの共分散行列 (R) */
CvMat* error_cov_pre; /* 今の時刻の誤差行列 (P'(k)):
P'(k)=A*P(k-1)*At + Q*/
CvMat* gain; /* 最適カルマンゲイン (K(k)):
K(k)=P'(k)*Ht*inv(H*P'(k)*Ht+R)*/
CvMat* error_cov_post; /* 更新された誤差の共分散行列 (P(k)):
P(k)=(I-K(k)*H)*P'(k) */
CvMat* temp1; /* テンポラリ行列 */
CvMat* temp2;
CvMat* temp3;
CvMat* temp4;
CvMat* temp5;
}
CvKalman;
構造体 CvKalman は,カルマンフィルタの状態を記憶しておくために利用されます.これは,関数 CreateKalman によって作成,関数 KalmanPredict と KalmanCorrect によって更新され ,関数 ReleaseKalman によって解放され ます.通常,この構造体は標準カルマンフィルタで利用されます(以下の表記法と式は,優れたカルマンフィルタのチュートリアルである Welch95 から引用しました)
ここで, : 時刻 におけるシステムの状態, : 時刻 における観測値, : 時刻 における制御入力,を表します.
また, と はそれぞれ,正規分布に従うプロセスノイズ,および観測ノイズです:
つまり,
プロセスノイズの共分散行列,定数あるいは変数, 観測ノイズの共分散行列,定数あるいは変数
標準カルマンフィルタの場合,全ての行列:A, B, H, Q, R は, CreateKalman によって構造体 CvKalman が確保された後で1度だけ初期化されます.しかし,拡張カルマンフィルタの式を現在のシステム状態周辺において線形化することで,拡張カルマンフィルタをシミュレートするために,同じ構造体と同じ関数が利用されることがあります.この場合,A, B, H (おそらく,Q と R も)毎ステップ更新されます.
カルマンフィルタの構造の領域を確保します.
パラメタ: |
|
---|
この関数は,構造体 CvKalman と,そのメンバであるすべての行列の領域を確保し,何らかの方法で初期化します.
モデルの状態を更新します.
パラメタ: |
|
---|
この関数は,モデル状態に対する観測ベクトルが与えられると,それに基づき確率モデル状態を更新します:
ここで
与えられた観測 ( mesurement パラメータ) | |
---|---|
カルマン「ゲイン」行列 |
です. この関数は,更新された状態を kalman->state_post に格納し,そのポインタを返します.
Example. Using Kalman filter to track a rotating point
#include "cv.h"
#include "highgui.h"
#include <math.h>
int main(int argc, char** argv)
{
/* 行列データ A */
const float A[] = { 1, 1, 0, 1 };
IplImage* img = cvCreateImage( cvSize(500,500), 8, 3 );
CvKalman* kalman = cvCreateKalman( 2, 1, 0 );
/* 状態 (phi, delta_phi) - 角度,角度の変化量 */
CvMat* state = cvCreateMat( 2, 1, CV_32FC1 );
CvMat* process_noise = cvCreateMat( 2, 1, CV_32FC1 );
/* phi (角度) だけが観測される */
CvMat* measurement = cvCreateMat( 1, 1, CV_32FC1 );
CvRandState rng;
int code = -1;
cvRandInit( &rng, 0, 1, -1, CV_RAND_UNI );
cvZero( measurement );
cvNamedWindow( "Kalman", 1 );
for(;;)
{
cvRandSetRange( &rng, 0, 0.1, 0 );
rng.disttype = CV_RAND_NORMAL;
cvRand( &rng, state );
memcpy( kalman->transition_matrix->data.fl, A, sizeof(A));
cvSetIdentity( kalman->measurement_matrix, cvRealScalar(1) );
cvSetIdentity( kalman->process_noise_cov, cvRealScalar(1e-5) );
cvSetIdentity( kalman->measurement_noise_cov, cvRealScalar(1e-1) );
cvSetIdentity( kalman->error_cov_post, cvRealScalar(1));
/* 初期状態をランダムに選択 */
cvRand( &rng, kalman->state_post );
rng.disttype = CV_RAND_NORMAL;
for(;;)
{
#define calc_point(angle) \
cvPoint( cvRound(img->width/2 + img->width/3*cos(angle)), \
cvRound(img->height/2 - img->width/3*sin(angle)))
float state_angle = state->data.fl[0];
CvPoint state_pt = calc_point(state_angle);
/* 点の位置を推定 */
const CvMat* prediction = cvKalmanPredict( kalman, 0 );
float predict_angle = prediction->data.fl[0];
CvPoint predict_pt = calc_point(predict_angle);
float measurement_angle;
CvPoint measurement_pt;
cvRandSetRange( &rng,
0,
sqrt(kalman->measurement_noise_cov->data.fl[0]),
0 );
cvRand( &rng, measurement );
/* 観測値を生成 */
cvMatMulAdd( kalman->measurement_matrix, state, measurement, measurement );
measurement_angle = measurement->data.fl[0];
measurement_pt = calc_point(measurement_angle);
/* 点をプロット */
#define draw_cross( center, color, d ) \
cvLine( img, cvPoint( center.x - d, center.y - d ), \
cvPoint( center.x + d, center.y + d ), \
color, 1, 0 ); \
cvLine( img, cvPoint( center.x + d, center.y - d ), \
cvPoint( center.x - d, center.y + d ), \
color, 1, 0 )
cvZero( img );
draw_cross( state_pt, CV_RGB(255,255,255), 3 );
draw_cross( measurement_pt, CV_RGB(255,0,0), 3 );
draw_cross( predict_pt, CV_RGB(0,255,0), 3 );
cvLine( img, state_pt, predict_pt, CV_RGB(255,255,0), 3, 0 );
/* カルマンフィルタの状態を更新 */
cvKalmanCorrect( kalman, measurement );
cvRandSetRange( &rng,
0,
sqrt(kalman->process_noise_cov->data.fl[0]),
0 );
cvRand( &rng, process_noise );
cvMatMulAdd( kalman->transition_matrix,
state,
process_noise,
state );
cvShowImage( "Kalman", img );
code = cvWaitKey( 100 );
if( code > 0 ) /* キーを押すと現在のシミュレーションを終了 */
break;
}
if( code == 27 ) /* ESC キーでプログラム終了 */
break;
}
return 0;
}
次のモデル状態を推定します.
パラメタ: |
|
---|
この関数は,現在の状態から次の確率モデル状態を推定し, kalman->state_pre に格納します:
ここで
状態の推定値 kalman->state_pre , | |
---|---|
前回の更新された状態の推定値 kalman->state_post (最初は何らかの方法で初期化される,デフォルトではゼロベクトル), | |
制御入力 ( control パラメータ), | |
今の時刻の誤差の共分散行列 kalman->error_cov_pre | |
前回の更新された誤差の共分散行列 kalman->error_cov_post (最初は何らかの方法で初期化される,デフォルトでは単位行列), |
この関数は,状態の推定値を返します.
KalmanCorrect と同義
KalmanPredict と同義
バックプロジェクション上の物体中心を求めます.
パラメタ: |
|
---|
この関数は,物体のバック工プロジェクションと探索窓の初期位置が与えられると,その物体の中心を求めるための反復計算を行います.反復計算は,探索窓中心の移動量が与えられた閾値より小さくなるか,あるいは関数の反復数が最大値に達するまで続けられます.また,この関数は,その反復数を返します.
ConDensationフィルタ構造体を解放します.
パラメタ: |
|
---|
この関数は,構造体 condens と,この構造体のために確保されたメモリすべてを解放します.
モーション全体を個別のモーションに分解します.
パラメタ: |
|
---|
この関数は,すべてのモーション成分を検出し,それぞれ個別の値を用いて seg_mask にマークします.これは,各モーション成分毎に,構造体 CvConnectedComp のシーケンスを返します.その後,特定の成分を抽出するマスク Cmp を利用し, CalcGlobalOrientation によって全てのモーション成分のモーション方向が計算されます.
そのエネルギーが最小となるように輪郭位置を変更します.
パラメタ: |
|
---|
この関数は,内部エネルギーと外部エネルギーの総和が最小になるように輪郭点を更新します.内部エネルギーは,輪郭形状に依存します(滑らかな輪郭ほど,内部エネルギーが小さくなります).また,外部エネルギーはエネルギー場に依存し,画像勾配を用いる場合は,画像エッジのようにエネルギーが極小値をとる場所において最小になります.
パラメータ criteria.epsilon は,1回の計算で最低何個の輪郭点が移動すれば反復計算が継続されるか,を規定します.
ある試行において,移動する輪郭点の個数が criteria.epsilon よりも少ないか,あるいは,関数の反復計算回数が criteria.max_iter に達した場合,この関数は終了します.
動作を表すシルエット画像を用いて,モーション履歴画像を更新します.
パラメタ: |
|
---|
この関数は,モーション履歴画像を以下のように更新します:
つまり,モーションが発生した場所のMHI(モーション履歴画像)ピクセルには,現在のタイムスタンプがセットされ,モーションが発生からある程度以上時間が経ったピクセルの値はクリアされます.