2012-05-02 19 views
6

私は今、私の顔検出プログラムのパフォーマンスを向上させるために数日間カルマンフィルタの操作を研究しています。私が集めた情報から、私はコードをまとめました。カルマンフィルタ部分のコードは以下の通りです。4つの入力パラメータを持つカルマンフィルタ

int Kalman(int X,int faceWidth,int Y,int faceHeight, IplImage *img1){ 
CvRandState rng; 
const float T = 0.1; 

// Initialize Kalman filter object, window, number generator, etc 
cvRandInit(&rng, 0, 1, -1, CV_RAND_UNI); 

//IplImage* img = cvCreateImage(cvSize(500,500), 8, 3); 
CvKalman* kalman = cvCreateKalman(4, 4, 0 ); 

// Initializing with random guesses 
// state x_k 
CvMat* state = cvCreateMat(4, 1, CV_32FC1); 
cvRandSetRange(&rng, 0, 0.1, 0); 
rng.disttype = CV_RAND_NORMAL; 
cvRand(&rng, state); 

// Process noise w_k 
CvMat* process_noise = cvCreateMat(4, 1, CV_32FC1); 

// Measurement z_k 
CvMat* measurement = cvCreateMat(4, 1, CV_32FC1); 
cvZero(measurement); 

/* create matrix data */ 
const float A[] = {  
     1, 0, T, 0, 
     0, 1, 0, T, 
     0, 0, 1, 0, 
     0, 0, 0, 1 
    }; 

const float H[] = {  
     1, 0, 0, 0, 
     0, 0, 0, 0, 
     0, 0, 1, 0, 
     0, 0, 0, 0 
    }; 

//Didn't use this matrix in the end as it gave an error:'ambiguous call to overloaded function' 
/* const float P[] = { 
     pow(320,2), pow(320,2)/T, 0, 0, 
     pow(320,2)/T, pow(320,2)/pow(T,2), 0, 0, 
     0, 0, pow(240,2), pow(240,2)/T, 
     0, 0, pow(240,2)/T, pow(240,2)/pow(T,2) 
     }; */ 

const float Q[] = { 
     pow(T,3)/3, pow(T,2)/2, 0, 0, 
     pow(T,2)/2, T, 0, 0, 
     0, 0, pow(T,3)/3, pow(T,2)/2, 
     0, 0, pow(T,2)/2, T 
     }; 

const float R[] = { 
     1, 0, 0, 0, 
     0, 0, 0, 0, 
     0, 0, 1, 0, 
     0, 0, 0, 0 
     }; 

//Copy created matrices into kalman structure 
memcpy(kalman->transition_matrix->data.fl, A, sizeof(A)); 
memcpy(kalman->measurement_matrix->data.fl, H, sizeof(H)); 
memcpy(kalman->process_noise_cov->data.fl, Q, sizeof(Q)); 
//memcpy(kalman->error_cov_post->data.fl, P, sizeof(P)); 
memcpy(kalman->measurement_noise_cov->data.fl, R, sizeof(R)); 

//Initialize other Kalman Filter parameters 
//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(1e-5)); 

/* choose initial state */ 
kalman->state_post->data.fl[0]=X; 
kalman->state_post->data.fl[1]=faceWidth; 
kalman->state_post->data.fl[2]=Y; 
kalman->state_post->data.fl[3]=faceHeight; 

//cvRand(&rng, kalman->state_post); 

/* predict position of point */ 
const CvMat* prediction=cvKalmanPredict(kalman,0); 

//generate measurement (z_k) 
cvRandSetRange(&rng, 0, sqrt(kalman->measurement_noise_cov->data.fl[0]), 0); 
cvRand(&rng, measurement); 
cvMatMulAdd(kalman->measurement_matrix, state, measurement, measurement); 

//Draw rectangles in detected face location 
cvRectangle(img1, 
      cvPoint(kalman->state_post->data.fl[0], kalman->state_post->data.fl[2]), 
      cvPoint(kalman->state_post->data.fl[1], kalman->state_post->data.fl[3]), 
      CV_RGB(0, 255, 0), 1, 8, 0); 

cvRectangle(img1, 
      cvPoint(prediction->data.fl[0], prediction->data.fl[2]), 
      cvPoint(prediction->data.fl[1], prediction->data.fl[3]), 
      CV_RGB(0, 0, 255), 1, 8, 0); 

cvShowImage("Kalman",img1); 

//adjust kalman filter state 
cvKalmanCorrect(kalman,measurement); 

cvMatMulAdd(kalman->transition_matrix, state, process_noise, state); 

return 0; 
} 

顔検出部(図示せず)では、検出された顔に対してボックスが描画される。 'X、Y、faceWidth and faceHeight'は、ボックスの座標と、カルマンフィルタに渡される幅と高さです。 'img1'は動画の現在のフレームです。

結果:

私は「state_post」と「予測」データ(コードに見られるように)から、二つの新しい四角形を取得しないが、それらのどれもが任意のより安定せずに描かれた最初のボックスよりもように見えるんカルマンフィルタ。

ここに私の質問は以下のとおりです。

  1. が初期化行列(遷移行列A、測定行列Hなど)されており、この4つの入力の場合のために正しいですか? (4つの入力の4 * 4行列など)
  2. すべての行列を恒等行列に設定できないのですか?
  3. 矩形をプロットするまで理論的に正しい方法はありますか?私はthisの例と、外部入力を使用しない本「Learning OpenCV」の例を続けました。

これについての助けがあれば幸いです!

答えて

4

イメージから直接測定する場合、H []は同一でなければなりません。 4つの測定値があり、対角線上でいくつかの値を0にすると、それらが正しくないときに期待される測定値(x * H)が0になります。カルマンフィルタのイノベーション(z-x * H)は高くなります。

また、測定誤差の共分散は1とは異なる可能性があるが、R []も対角でなければならない。座標を正規化した場合(幅=高さ= 1)、Rは0.01のようになります。ピクセル座標を扱っている場合、R = diagonal_onesは1ピクセルの誤差を意味し、それは問題ありません。 1,2,3,4などで試すことができます。

各フレームの状態を伝播するはずの遷移行列A []は、x、y、 v_xおよびv_y。あなたのモデルでは速度は言及せず、測定についてのみ話します。状態(顔の位置を記述する)と測定(状態を更新するために使用される)を混同しないように注意してください。あなたの状態は、位置、速度、加速度のいずれかであり、測定値は画像のn点になります。または、顔のxとyの位置。

これが役に立ちます。

+1

有益な回答ありがとうございました!私はこの段階のカルマンフィルタを省くことにしたので、何も変えられなかった。しかし、私は誰かがあなたの答えを見つけるのに役立つと確信しています!再度、感謝します。 – Kavo

関連する問題