Kalman滤波器的详细使用和讲解

       

         这两天一直在研究Kalman滤波器,刚开始开的时候对代码很不理解,但是没办法,谁叫哥就是学这个的呢,所以硬着头皮死看代码,以及看了一些关于对kalman滤波器的使用的博文,现在已经大致掌握kalman滤波器的使用步骤。(转自http://zhuyuge0.blog.163.com/blog/static/13230361420117541511810/)

         首先我们要了解kalman滤波器的基本知识,这样在之后的介绍能起到抛砖引玉的作用,当然还是和之前笔者关于opencv的博文一样,对于kalman的具体数学推导过程不做介绍,不过看了一下也不是很难,主要涉及到一些关于概率和线性代数的知识,有兴趣的朋友可以看下,还可以一起讨论一下,呵呵。

         好,下面进入正题,关于kalman滤波器的基本思想是若有一组强而合理的假设,给出系统的历史测量值,则可以最大化这些早前测量值的后验概率的系统状态模型。有的朋友可能对最大化后验概率概念不了解,它就是考虑早前的模型和新测量值的不确定性,在获得测量值之后,新建立的模型是具有最高正确概率的模型。

kalman filter的三条假设也有必要说一下:1、被建模型系统是线性的,即k时刻系统状态可以用某个矩阵与k-1时刻的乘机表达

2、影响测量的噪声是白噪声,即噪声与时间不相关;

3、噪声的本质是高斯分布的,即只用均值和协方差就可以准确为幅值建模。(以上知识可以参考于刘opencv learning)

下面开始使用kalman滤波器,在此之前,我们必须了解CvKalman的结构,还有cvCreateKalman、cvKalmanPredict、cvKalmanCorrect的使用方法和实现的作用(可以参照下面的代码示例),这些基本的就不详细介绍。

看了某位仁兄的博文,我发现他对kalman使用总结很到位,下面笔者在他的基础之上重新说明下Kalman滤波器的使用步骤:

Kalman滤波器的详细使用和讲解 - 后青春期 - 后青春期 的博客

 在这些过程中,第一步相对来说最复杂,我们光光利用cvcreatekalman建立滤波器是不够的,必须对其初始化,包括对CvKlaman中每个矩阵进行初始化(除了error_cov_pre和gain无需初始化,因为在刚开始时我们当然不会知道先验错误的相关矩形,而对于gain来说,它的计算需要用到error_cov_pre,所以gain(增益矩阵)也无需初始化),包括对transition_matrix(转移矩阵),control_matrix(控制矩阵),measurement_matrix(测量矩阵),process_noise_cov(处理噪声相相关矩阵),measurement_noise_cov(测量噪声相关矩阵),error_cov_post(后验错误矩阵),进行初始化。

下面采用一个简单的例子来讲解:

#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <cmath>
#include <vector>
#include <iostream>
using namespace std;
const int winHeight=600;
const int winWidth=800;
CvPoint mousePosition=cvPoint(winWidth>>1,winHeight>>1);
//mouse event callback
void mouseEvent(int event, int x, int y, int flags, void *param )
{
 if (event==CV_EVENT_MOUSEMOVE) {
  mousePosition=cvPoint(x,y);
 }
}
int main (void)
{
 //1.kalman filter setup
 const int stateNum=4;
 const int measureNum=2;
 CvKalman* kalman = cvCreateKalman( stateNum, measureNum, 0 );//state(x,y,detaX,detaY)
 CvMat* process_noise = cvCreateMat( stateNum, 1, CV_32FC1 );
 CvMat* measurement = cvCreateMat( measureNum, 1, CV_32FC1 );//measurement(x,y)
 CvRNG rng = cvRNG(-1);//这个函数也许有的朋友不知道,初始化随机数生成器的状态
 float A[stateNum][stateNum] ={//transition matrix传递矩阵
  1,0,1,0,
  0,1,0,1,
  0,0,1,0,
  0,0,0,1
 };
 memcpy( kalman->transition_matrix->data.fl,A,sizeof(A));//void *memcpy(void *dest, const void *src, size_t n);从源src所指的内存地址                                                                                                    // 的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
 cvSetIdentity(kalman->measurement_matrix,cvRealScalar(1) );//cvRealScalar是用value初始化val[0],0初始化val[1],val[2],val[3]
 cvSetIdentity(kalman->process_noise_cov,cvRealScalar(1e-5));//cvSetIdentity是初始化带单位的矩阵,第二个参数是赋给对角线的值
 cvSetIdentity(kalman->measurement_noise_cov,cvRealScalar(1e-1));
 cvSetIdentity(kalman->error_cov_post,cvRealScalar(1));
 //initialize post state of kalman filter at random

 cvRandArr(&rng,kalman->state_post,CV_RAND_UNI,cvRealScalar(0),cvRealScalar(winHeight>winWidth?winWidth:winHeight));
 CvFont font;//用随机数填充数组并更新RNG状态,CV_RAND_UNI表示均匀分布,随后两个参数表示随机数的上下界
 cvInitFont(&font,CV_FONT_HERSHEY_SCRIPT_COMPLEX,1,1);
//我的博客上有相关文章可以参考
 cvNamedWindow("kalman");
 cvSetMouseCallback("kalman",mouseEvent);
 IplImage* img=cvCreateImage(cvSize(winWidth,winHeight),8,3);
 while (1){
  //2.kalman prediction
  const CvMat* prediction=cvKalmanPredict(kalman,0);
  CvPoint predict_pt=cvPoint((int)prediction->data.fl[0],(int)prediction->data.fl[1]);
  //3.update measurement
  measurement->data.fl[0]=(float)mousePosition.x;
  measurement->data.fl[1]=(float)mousePosition.y;
  //4.update
  cvKalmanCorrect( kalman, measurement );  
  //draw 
  cvSet(img,cvScalar(255,255,255,0));
  cvCircle(img,predict_pt,5,CV_RGB(0,255,0),3);//predicted point with green
  cvCircle(img,mousePosition,5,CV_RGB(255,0,0),3);//current position with red
  char buf[256];
  sprintf_s(buf,256,"predicted position:(%3d,%3d)",predict_pt.x,predict_pt.y);
  cvPutText(img,buf,cvPoint(10,30),&font,CV_RGB(0,0,0));
  sprintf_s(buf,256,"current position :(%3d,%3d)",mousePosition.x,mousePosition.y);
  cvPutText(img,buf,cvPoint(10,60),&font,CV_RGB(0,0,0));
  
  cvShowImage("kalman", img);
  int key=cvWaitKey(3);
  if (key==27){//esc   
   break;   
  }
 }      
 cvReleaseImage(&img);
 cvReleaseKalman(&kalman);
 return 0;
}

至于运行结果就不赋图了,很多博文都有这段代码的运行结果。

掌握这段程序之后我们可以再去读于刘书中的kalman滤波器跟踪一个旋转点的程序,也没有什么难点了。。。。转载请注明来

发布了4 篇原创文章 · 获赞 4 · 访问量 4万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章