2012-05-02 11 views
6

Ho studiato il funzionamento del filtro Kalman per un paio di giorni per migliorare le prestazioni del mio programma di rilevamento del volto. Dalle informazioni che ho raccolto ho messo insieme un codice. Il codice per la parte del filtro di Kalman è il seguente.Filtri Kalman con quattro parametri di input

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; 
} 

Nella parte di rilevamento del volto (non mostrata), viene disegnata una casella per il viso rilevato. 'X, Y, faceWidth e faceHeight' sono le coordinate della casella e la larghezza e l'altezza passate nel filtro di Kalman. 'img1' è il frame corrente di un video.

Risultati:

Anche se io capisco due nuovi rettangoli dal 'state_post' e dei dati 'predizione' (come si vede nel codice), nessuno di loro sembrano essere più stabili rispetto al dialogo iniziale disegnato senza il filtro di Kalman.

Ecco le mie domande:

  1. Sono le matrici inizializzati (transizione matrice A, matrice di misura H, ecc), corretto per questo caso di ingresso di quattro? (es. 4 * 4 matrici per quattro ingressi?)
  2. Non possiamo impostare ogni matrice come matrice di identità?
  3. Il metodo che ho seguito fino alla creazione dei rettangoli è teoricamente corretto? Ho seguito gli esempi in this e nel libro "Learning OpenCV" che non utilizza input esterni.

Qualsiasi aiuto in merito sarebbe molto apprezzato!

risposta

4

H [] deve essere l'identità se si misura direttamente dall'immagine. Se hai 4 misure e fai 0 valori sulla diagonale, stai facendo quelle misure attese (x * H) 0, quando non è vero. Quindi l'innovazione (z- x * H) sul filtro kalman sarà alta.

R [] dovrebbe anche essere diagonale, anche se la covarianza dell'errore di misurazione può essere diversa da quella. Se hai coordinate normalizzate (larghezza = altezza = 1), R potrebbe essere qualcosa come 0,01. Se hai a che fare con le coordinate dei pixel, R = diagonal_ones significa un errore di un pixel, e va bene. Puoi provare con 2,3,4, ecc ...

La tua matrice di transizione A [], che dovrebbe propagare lo stato su ciascun fotogramma, sembra una matrice di transizione per uno stato composto da x, y, v_x e v_y. Non parli di velocità nel tuo modello, parli solo di misurazioni. Fai attenzione, non confondere lo stato (descrive la posizione del viso) con le misure (utilizzato per aggiornare lo stato). Il tuo stato può essere posizione, velocità e accelerazione e le tue misurazioni possono essere n punti nell'immagine. O la posizione xey del viso.

Spero che questo aiuti.

+1

Grazie mille per la risposta informativa! Non ho potuto cambiare nulla, anche se ho deciso di lasciare fuori il filtro di Kalman per questa fase. Ma sono sicuro che qualcuno troverà utile la tua risposta! Grazie ancora. – Kavo