6

私は、顔検出プログラムのパフォーマンスを向上させるために、カルマンフィルターの動作を数日間研究しています。収集した情報から、コードをまとめました。カルマンフィルター部分のコードは次のとおりです。

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、faceHeight」は、ボックスの座標と、カルマンフィルターに渡される幅と高さです。「img1」は、ビデオの現在のフレームです。

結果:

'state_post'および'prediction'データから2つの新しい長方形を取得しますが(コードに表示されているように)、カルマンフィルターなしで描画された最初のボックスよりも安定しているようには見えません。

これが私の質問です:

  1. 行列は初期化されていますか(遷移行列A、測定行列Hなど)、この4つの入力ケースに対して正しいですか?(例:4つの入力に対して4 * 4の行列?)
  2. すべての行列を単位行列に設定することはできませんか?
  3. 長方形をプロットするまで私が従った方法は理論的に正しいですか?私はこれと外部入力を使用しない本「LearningOpenCV」の例に従いました。

これに関する助けをいただければ幸いです。

4

1 に答える 1

4

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

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

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

お役に立てれば。

于 2012-05-24T15:45:31.830 に答える