1793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/video/tracking.hpp"
2793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/highgui/highgui.hpp"
3793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
4793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include <stdio.h>
5793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
6793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerusing namespace cv;
7793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
8793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic inline Point calcPoint(Point2f center, double R, double angle)
9793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
10793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return center + Point2f((float)cos(angle), (float)-sin(angle))*(float)R;
11793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
12793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
13793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic void help()
14793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
15793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    printf( "\nExample of c calls to OpenCV's Kalman filter.\n"
16793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler"   Tracking of rotating point.\n"
17793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler"   Rotation speed is constant.\n"
18793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler"   Both state and measurements vectors are 1D (a point angle),\n"
19793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler"   Measurement is the real point angle + gaussian noise.\n"
20793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler"   The real and the estimated points are connected with yellow line segment,\n"
21793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler"   the real and the measured points are connected with red line segment.\n"
22793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler"   (if Kalman filter works correctly,\n"
23793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler"    the yellow segment should be shorter than the red one).\n"
24793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            "\n"
25793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler"   Pressing any key (except ESC) will reset the tracking with a different speed.\n"
26793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler"   Pressing ESC will stop the program.\n"
27793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            );
28793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
29793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
30793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerint main(int, char**)
31793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
32793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    help();
33793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Mat img(500, 500, CV_8UC3);
34793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    KalmanFilter KF(2, 1, 0);
35793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Mat state(2, 1, CV_32F); /* (phi, delta_phi) */
36793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Mat processNoise(2, 1, CV_32F);
37793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Mat measurement = Mat::zeros(1, 1, CV_32F);
38793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    char code = (char)-1;
39793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
40793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for(;;)
41793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
42793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        randn( state, Scalar::all(0), Scalar::all(0.1) );
43793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        KF.transitionMatrix = (Mat_<float>(2, 2) << 1, 1, 0, 1);
44793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
45793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        setIdentity(KF.measurementMatrix);
46793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        setIdentity(KF.processNoiseCov, Scalar::all(1e-5));
47793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        setIdentity(KF.measurementNoiseCov, Scalar::all(1e-1));
48793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        setIdentity(KF.errorCovPost, Scalar::all(1));
49793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
50793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        randn(KF.statePost, Scalar::all(0), Scalar::all(0.1));
51793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
52793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for(;;)
53793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
54793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            Point2f center(img.cols*0.5f, img.rows*0.5f);
55793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            float R = img.cols/3.f;
56793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            double stateAngle = state.at<float>(0);
57793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            Point statePt = calcPoint(center, R, stateAngle);
58793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
59793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            Mat prediction = KF.predict();
60793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            double predictAngle = prediction.at<float>(0);
61793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            Point predictPt = calcPoint(center, R, predictAngle);
62793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
63793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            randn( measurement, Scalar::all(0), Scalar::all(KF.measurementNoiseCov.at<float>(0)));
64793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
65793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            // generate measurement
66793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            measurement += KF.measurementMatrix*state;
67793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
68793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            double measAngle = measurement.at<float>(0);
69793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            Point measPt = calcPoint(center, R, measAngle);
70793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
71793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            // plot points
72793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            #define drawCross( center, color, d )                                        \
73793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                line( img, Point( center.x - d, center.y - d ),                          \
74793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                             Point( center.x + d, center.y + d ), color, 1, LINE_AA, 0); \
75793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                line( img, Point( center.x + d, center.y - d ),                          \
76793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                             Point( center.x - d, center.y + d ), color, 1, LINE_AA, 0 )
77793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
78793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            img = Scalar::all(0);
79793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            drawCross( statePt, Scalar(255,255,255), 3 );
80793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            drawCross( measPt, Scalar(0,0,255), 3 );
81793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            drawCross( predictPt, Scalar(0,255,0), 3 );
82793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            line( img, statePt, measPt, Scalar(0,0,255), 3, LINE_AA, 0 );
83793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            line( img, statePt, predictPt, Scalar(0,255,255), 3, LINE_AA, 0 );
84793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
85793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if(theRNG().uniform(0,4) != 0)
86793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                KF.correct(measurement);
87793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
88793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            randn( processNoise, Scalar(0), Scalar::all(sqrt(KF.processNoiseCov.at<float>(0, 0))));
89793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            state = KF.transitionMatrix*state + processNoise;
90793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
91793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            imshow( "Kalman", img );
92793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            code = (char)waitKey(100);
93793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
94793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( code > 0 )
95793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                break;
96793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
97793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( code == 27 || code == 'q' || code == 'Q' )
98793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            break;
99793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
100793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
101793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return 0;
102793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
103