칼만 필터(Kalman Filter)

컴퓨터비전/영상처리 2015. 4. 6. 01:01

칼만 필터는 부정확한 측정값(관찰, 혹은 예측값)으로부터 오차를 최소화 하는 추정치를 반복적으로 

계산하는 방법이다. 가우시안 잡음(Gaussian noise)인 경우에 최적의 추정량을 구할 수 있다.


Wan, Eric A., and Rudolph Van Der Merwe. "The unscented Kalman filter for nonlinear estimation." 

Adaptive Systems for Signal Processing, Communications, and Control Symposium 2000. AS-SPCC. 

The IEEE 2000. IEEE, 2000.


칼만 필터 프로세스 방정식과 측정 방정식은 다음과 같다.





칼만 필터는 초기화 이후 예측(predict) 위 단계를 계속 반복하면서 추정치를 구한다.

측정 잡음의 공분산 R이 아주 크면, 칼만이득 K가 작아져서 다음 단계의 추정치를 계산할 때 현재의 측정값이 무시된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <cv.h>
#include <highgui.h>
#include <iostream>
 
using namespace std;
using namespace cv;
 
int main()
{
    // Greq Welch and Gary Bishop, "An Introduction to the Kalman Filter", 2006.
    // Estimating a Random Constant
 
    IplImage *dstImage = cvCreateImage(cvSize(512512), IPL_DEPTH_8U, 3);
    cvSet(dstImage, CV_RGB(255255255));
 
    IplImage *pImage = cvCreateImage(cvSize(512512), IPL_DEPTH_8U, 3);
    cvSet(pImage, CV_RGB(255255255));
 
    cvNamedWindow("dstImage");
    cvNamedWindow("pImage");
 
    CvRNG rng_state = cvRNG(0xffffffff);
 
    int t, count = 50;
    double x = -0.37727;
 
    int step = dstImage->width / count;
 
    CvMat *= cvCreateMat(count, 1, CV_32FC1);
    cvRandArr(&rng_state, z, CV_RAND_NORMAL, cvRealScalar(x), cvRealScalar(0.1));
 
    ////////////////////////////////
    //        kalman filter       //
    ////////////////////////////////
    double Q = 1e-5// process variance
    double R = (0.1* (0.1); // estimate of measurement variance
    //double R = 1.0; // estimate of measurement variance
    //double R = 0.0001; // estimate of measurement variance
 
    CvMat *xhat = cvCreateMat(count, 1, CV_32FC1); // posteriori estimate of x
    CvMat *= cvCreateMat(count, 1, CV_32FC1); // posteriori error estimate 
    CvMat *xhatminus = cvCreateMat(count, 1, CV_32FC1); // priori estimate of x
    CvMat *Pminus = cvCreateMat(count, 1, CV_32FC1); // priori error estimate
    CvMat *= cvCreateMat(count, 1, CV_32FC1); // kalman gain
 
    // to access as an array in 1D matrix
    float *xhatA = xhat->data.fl;
    float *PA = P->data.fl;
    float *xhatminusA = xhatminus->data.fl;
    float *PminusA = Pminus->data.fl;
    float *KA = K->data.fl;
    float *zA = z->data.fl;
 
    xhatA[0= 0.0;
    PA[0= 1.0;
 
    for (t = 1; t < count; t++)
    {
        //predict
        xhatminusA[t] = xhatA[t - 1];
        PminusA[t] = PA[t - 1+ Q;
 
        //update
        KA[t] = PminusA[t] / (PminusA[t] + R);
        xhatA[t] = xhatminusA[t] + KA[t] * (zA[t] - xhatminusA[t]);
        PA[t] = (- KA[t]) * PminusA[t];
    }
 
 
    //drawing values
    double minVal, maxVal;
    cvMinMaxLoc(z, &minVal, &maxVal);
    double scale = dstImage->height / (maxVal - minVal);
    printf("observations, z : minVal = %f, maxVal = %f\n", minVal, maxVal);
 
    //drawing the truth value, x = -0.37727
    CvPoint pt1, pt2;
    pt1.x = 0;
    pt1.y = dstImage->height - cvRound(scale * x - scale*minVal);
 
    pt2.x = dstImage->width;
    pt2.y = dstImage->height - cvRound(scale * x - scale*minVal);
    cvLine(dstImage, pt1, pt2, CV_RGB(00255), 2);
 
    //drawing the noisy measurements, observations, z
    for (t = 0; t < count; t++)
    {
        pt1.x = t*step;
        pt1.y = dstImage->height - cvRound(scale * zA[t] - scale * minVal);
        cvCircle(dstImage, pt1, 3, CV_RGB(25500), 2);
    }
 
    //drawing the filter estimate, xhat
    pt1.x = 0;
    pt1.y = dstImage->height - cvRound(scale * xhatA[0- scale * minVal);
 
    for (t = 1; t < count; t++)
    {
        pt2.x = t*step;
        pt2.y = dstImage->height - cvRound(scale * xhatA[t] - scale * minVal);
        cvLine(dstImage, pt1, pt2, CV_RGB(02550), 2);
        pt1 = pt2;
    }
 
    //drawing the error covariance, P
 
    cvMinMaxLoc(P, &minVal, &maxVal);
    scale = pImage->height / (maxVal - minVal);
    printf("error covariance, P : minVal = %f, maxVal = %f\n", minVal, maxVal);
 
    pt1.x = 0;
    pt1.y = pImage->height - cvRound(scale * PA[0- scale * minVal);
 
    for (t = 1; t < count; t++)
    {
        pt2.x = t*step;
        pt2.y = pImage->height - cvRound(scale * PA[t] - scale*minVal);
        //printf("PA[%d] = %f\n", t, PA[t]);
        cvLine(pImage, pt1, pt2, CV_RGB(25500), 2);
        pt1 = pt2;
    }
 
    cvShowImage("dstImage", dstImage);
    cvShowImage("pImage", pImage);
 
    cvSaveImage("dstImage.jpg", dstImage);
    cvSaveImage("pImage.jpg", pImage);
    
    cvWaitKey(0);
 
    cvReleaseMat(&z);
    cvReleaseMat(&xhat);
    cvReleaseMat(&P);
    cvReleaseMat(&xhatminus);
    cvReleaseMat(&Pminus);
    cvReleaseMat(&K);
 
    cvReleaseImage(&dstImage);
    cvReleaseImage(&pImage);
}
cs