1 | |
2 | Tracking of rotating point.
|
3 | Rotation speed is constant.
|
4 | Both state and measurements vectors are 1D (a point angle),
|
5 | Measurement is the real point angle + gaussian noise.
|
6 | The real and the estimated points are connected with yellow line segment,
|
7 | the real and the measured points are connected with red line segment.
|
8 | (if Kalman filter works correctly,
|
9 | the yellow segment should be shorter than the red one).
|
10 | Pressing any key (except ESC) will reset the tracking with a different speed.
|
11 | Pressing ESC will stop the program.
|
12 | */
|
13 |
|
14 |
|
15 | #include <cv.h>
|
16 | #include <highgui.h>
|
17 | #include <cmath>
|
18 |
|
19 | using namespace std;
|
20 | using namespace cv;
|
21 |
|
22 | int main(int argc, char** argv)
|
23 | {
|
24 | const float A[] = { 1, 1, 0, 1 };
|
25 |
|
26 | Mat img = Mat( Size(500,500), CV_8UC3 );
|
27 | KalmanFilter kalman = KalmanFilter( 2, 1, 0 );
|
28 | Mat state = Mat( 2, 1, CV_32FC1 );
|
29 | Mat process_noise = Mat( 2, 1, CV_32FC1 );
|
30 | Mat measurement = Mat::zeros( 1, 1, CV_32FC1 );
|
31 | RNG rng = RNG(-1);
|
32 | char code = -1;
|
33 |
|
34 |
|
35 | namedWindow( "Kalman", 1 );
|
36 |
|
37 | for(;;)
|
38 | {
|
39 | rng.fill(state,RNG::NORMAL,Scalar(0),Scalar(0.1));
|
40 |
|
41 | memcpy( kalman.transitionMatrix.data, A, sizeof(float)*sizeof(A));
|
42 | setIdentity( kalman.measurementMatrix, Scalar(1.0) );
|
43 | setIdentity( kalman.processNoiseCov, Scalar(1e-5) );
|
44 | setIdentity( kalman.measurementNoiseCov, Scalar(1e-1) );
|
45 | setIdentity( kalman.errorCovPost, Scalar(1));
|
46 | rng.fill(kalman.statePost, RNG::NORMAL, Scalar(0.0), Scalar(0.1) );
|
47 |
|
48 | for(;;)
|
49 | {
|
50 | #define calc_point(angle) \
|
51 | Point( cvRound(img.cols/2 + img.cols/3*cos(angle)), \
|
52 | cvRound(img.cols/2 - img.cols/3*sin(angle)))
|
53 |
|
54 | float state_angle = state.ptr<float>(0)[0];
|
55 | Point state_pt = calc_point(state_angle);
|
56 |
|
57 | const Mat prediction = kalman.predict();
|
58 | float predict_angle = prediction.ptr<float>(0)[0];
|
59 | Point predict_pt = calc_point(predict_angle);
|
60 | float measurement_angle;
|
61 | Point measurement_pt;
|
62 |
|
63 | rng.fill(measurement, RNG::NORMAL, Scalar(0),
|
64 | Scalar(sqrt(kalman.measurementNoiseCov.ptr<float>(0)[0])) );
|
65 |
|
66 |
|
67 | measurement=kalman.measurementMatrix*state+measurement;
|
68 |
|
69 | measurement_angle = measurement.ptr<float>(0)[0];
|
70 | measurement_pt = calc_point(measurement_angle);
|
71 |
|
72 |
|
73 | #define draw_cross( center, color, d ) \
|
74 | line( img, Point( center.x - d, center.y - d ), \
|
75 | Point( center.x + d, center.y + d ), color, 1, CV_AA, 0); \
|
76 | line( img, Point( center.x + d, center.y - d ), \
|
77 | Point( center.x - d, center.y + d ), color, 1, CV_AA, 0 )
|
78 |
|
79 | img.setTo(Scalar(0));
|
80 | draw_cross( state_pt, Scalar(255,255,255), 3 );
|
81 | draw_cross( measurement_pt, Scalar(255,0,0), 3 );
|
82 | draw_cross( predict_pt, CV_RGB(0,255,0), 3 );
|
83 | line( img, state_pt, measurement_pt, CV_RGB(255,0,0), 3, CV_AA, 0 );
|
84 | line( img, state_pt, predict_pt, CV_RGB(255,255,0), 3, CV_AA, 0 );
|
85 |
|
86 | kalman.correct( measurement );
|
87 |
|
88 | rng.fill(process_noise, RNG::NORMAL, Scalar(0),
|
89 | Scalar(sqrt(kalman.processNoiseCov.ptr<float>(0)[0])));
|
90 | state=kalman.transitionMatrix*state+process_noise;
|
91 |
|
92 | imshow( "Kalman", img );
|
93 | code = (char) waitKey( 100 );
|
94 |
|
95 | if( code > 0 )
|
96 | break;
|
97 |
|
98 | }
|
99 | if( code == 27 || code == 'q' || code == 'Q' )
|
100 | break;
|
101 |
|
102 | }
|
103 |
|
104 |
|
105 | return 0;
|
106 | }
|
107 |
|