kalman.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. #include "opencv2/video/tracking.hpp"
  2. #include "opencv2/highgui.hpp"
  3. #include "opencv2/core/cvdef.h"
  4. #include <stdio.h>
  5. using namespace cv;
  6. static inline Point calcPoint(Point2f center, double R, double angle)
  7. {
  8. return center + Point2f((float)cos(angle), (float)-sin(angle))*(float)R;
  9. }
  10. static void help()
  11. {
  12. printf( "\nExample of c calls to OpenCV's Kalman filter.\n"
  13. " Tracking of rotating point.\n"
  14. " Point moves in a circle and is characterized by a 1D state.\n"
  15. " state_k+1 = state_k + speed + process_noise N(0, 1e-5)\n"
  16. " The speed is constant.\n"
  17. " Both state and measurements vectors are 1D (a point angle),\n"
  18. " Measurement is the real state + gaussian noise N(0, 1e-1).\n"
  19. " The real and the measured points are connected with red line segment,\n"
  20. " the real and the estimated points are connected with yellow line segment,\n"
  21. " the real and the corrected estimated points are connected with green line segment.\n"
  22. " (if Kalman filter works correctly,\n"
  23. " the yellow segment should be shorter than the red one and\n"
  24. " the green segment should be shorter than the yellow one)."
  25. "\n"
  26. " Pressing any key (except ESC) will reset the tracking.\n"
  27. " Pressing ESC will stop the program.\n"
  28. );
  29. }
  30. int main(int, char**)
  31. {
  32. help();
  33. Mat img(500, 500, CV_8UC3);
  34. KalmanFilter KF(2, 1, 0);
  35. Mat state(2, 1, CV_32F); /* (phi, delta_phi) */
  36. Mat processNoise(2, 1, CV_32F);
  37. Mat measurement = Mat::zeros(1, 1, CV_32F);
  38. char code = (char)-1;
  39. for(;;)
  40. {
  41. img = Scalar::all(0);
  42. state.at<float>(0) = 0.0f;
  43. state.at<float>(1) = 2.f * (float)CV_PI / 6;
  44. KF.transitionMatrix = (Mat_<float>(2, 2) << 1, 1, 0, 1);
  45. setIdentity(KF.measurementMatrix);
  46. setIdentity(KF.processNoiseCov, Scalar::all(1e-5));
  47. setIdentity(KF.measurementNoiseCov, Scalar::all(1e-1));
  48. setIdentity(KF.errorCovPost, Scalar::all(1));
  49. randn(KF.statePost, Scalar::all(0), Scalar::all(0.1));
  50. for(;;)
  51. {
  52. Point2f center(img.cols*0.5f, img.rows*0.5f);
  53. float R = img.cols/3.f;
  54. double stateAngle = state.at<float>(0);
  55. Point statePt = calcPoint(center, R, stateAngle);
  56. Mat prediction = KF.predict();
  57. double predictAngle = prediction.at<float>(0);
  58. Point predictPt = calcPoint(center, R, predictAngle);
  59. // generate measurement
  60. randn( measurement, Scalar::all(0), Scalar::all(KF.measurementNoiseCov.at<float>(0)));
  61. measurement += KF.measurementMatrix*state;
  62. double measAngle = measurement.at<float>(0);
  63. Point measPt = calcPoint(center, R, measAngle);
  64. // correct the state estimates based on measurements
  65. // updates statePost & errorCovPost
  66. KF.correct(measurement);
  67. double improvedAngle = KF.statePost.at<float>(0);
  68. Point improvedPt = calcPoint(center, R, improvedAngle);
  69. // plot points
  70. img = img * 0.2;
  71. drawMarker(img, measPt, Scalar(0, 0, 255), cv::MARKER_SQUARE, 5, 2);
  72. drawMarker(img, predictPt, Scalar(0, 255, 255), cv::MARKER_SQUARE, 5, 2);
  73. drawMarker(img, improvedPt, Scalar(0, 255, 0), cv::MARKER_SQUARE, 5, 2);
  74. drawMarker(img, statePt, Scalar(255, 255, 255), cv::MARKER_STAR, 10, 1);
  75. // forecast one step
  76. Mat test = Mat(KF.transitionMatrix*KF.statePost);
  77. drawMarker(img, calcPoint(center, R, Mat(KF.transitionMatrix*KF.statePost).at<float>(0)),
  78. Scalar(255, 255, 0), cv::MARKER_SQUARE, 12, 1);
  79. line( img, statePt, measPt, Scalar(0,0,255), 1, LINE_AA, 0 );
  80. line( img, statePt, predictPt, Scalar(0,255,255), 1, LINE_AA, 0 );
  81. line( img, statePt, improvedPt, Scalar(0,255,0), 1, LINE_AA, 0 );
  82. randn( processNoise, Scalar(0), Scalar::all(sqrt(KF.processNoiseCov.at<float>(0, 0))));
  83. state = KF.transitionMatrix*state + processNoise;
  84. imshow( "Kalman", img );
  85. code = (char)waitKey(1000);
  86. if( code > 0 )
  87. break;
  88. }
  89. if( code == 27 || code == 'q' || code == 'Q' )
  90. break;
  91. }
  92. return 0;
  93. }