//本代码是关于learning OpenCV 394页的代码写的注释(前提:我买的书不是盗版的话。。。。)
#include "cv.h"
#include "highgui.h"
#include "math.h"
#define phi2xy(mat) \
cvPoint( cvRound(img->width/2 + img->width/3*cos(mat->data.fl[0])),\
cvRound( img->height/2 - img->width/3*sin(mat->data.fl[0])) )
//注释下, 作者指定圆心在图片width/2, height/2处, 圆周运动半径是width/3
using namespace cv;
//我们从main函数开始解析,去除了#include "cvx_defs.h"...我试了在vs2015与qt5.6和qt.5.9上由两个人分别配置的opencv2.4.9
//和2.4.13以及。3.1.0的环境,都没有这个头文件,网上居然说有。。。。我不知道是我太菜还是他们直接贴代码。。跪求配置出来的人贴图
int main()
{
//创建卡尔曼滤波对象,窗口,随机数生成器
cvNamedWindow("Boss Kalman",1);
CvRandState rng; //创建生成随机数的结构体
// typedef struct CvRandState
// {
// CvRNG state; //64位无符号整数
// int disttype;
// CvScalar param[2];
// }
// CvRandState;
cvRandInit(&rng,0,1,-1,CV_RAND_UNI);
//CvRandState结构,随机分布下限,随机分布上限,时间种子,可以用-1代替,也可以用getTickCount 代替
IplImage *img=cvCreateImage(cvSize(500,500),8,3); //长宽500,8位,三通道
CvKalman *kalman=cvCreateKalman(2,1,0);
//状态变量维数2,测量值维数1,控制维数0,
//空间分配完毕,接下来我们为状态x_k,过程噪声w_k,测量值z_k,传递矩阵F创建矩阵
//公式如下 Ⅰ,x_k^-=Fx_(k-1)+Bu_(k-1)+w_k
//注释:这里Bu_(k-1)项忽略,因为传入的控制维数为0,F是2x2矩阵,因为状态变量维数为2(即右侧的x_(k-1)是2x1的矩阵),分别是角度位置和角度。
//自然过程噪声也应该是2x1的矩阵,x_k^-(先验估计)计算出后,带入下列公式
//Ⅱ x_k=x_k^-+K_k(z_k^-+H_k*x_k^-)
//P_k=(I-K_k*H_k)P_k
//初始化操作
//x_k 为[角度位置(phi),角速度(delta_phi)]^T
//传递矩阵即为:[(1,dt),[0,1]],F*x_k相乘即为[(phi+velocity*dt),(velocity)],线代知识,哈哈
CvMat *x_k=cvCreateMat(2,1,CV_32FC1);
cvRandSetRange(&rng,0,0.1,0);
//rng_state,生成的随机数下界,生成的随机数上界
//index
//The 0-based index of dimension/channel for which the parameter are changed,
//-1 means changing the parameters for all dimensions.
rng.disttype=CV_RAND_NORMAL; //设为正态分布
cvRand(&rng,x_k); //将x_k的数据随机化
CvMat *w_k=cvCreateMat(2,1,CV_32FC1);
//测量数据,只有角度位置
CvMat *z_k=cvCreateMat(1,1,CV_32FC1);
cvZero(z_k);
//设置传递矩阵
const float F[]={1,1,0,1};
memcpy(kalman->transition_matrix->data.fl,F,sizeof(F));
//初始化kalman的其他参数
cvSetIdentity(kalman->measurement_matrix,cvRealScalar(1));
//初始化测试协方差矩阵
cvSetIdentity(kalman->process_noise_cov,cvRealScalar(1e-5));
//初始过程协方差矩阵
cvSetIdentity(kalman->measurement_noise_cov,cvRealScalar(1e-1));
//初始测量噪音协方差矩阵
cvSetIdentity(kalman->error_cov_post,cvRealScalar(1));
//测量误差矩阵,v_k.
cvRand(&rng,kalman->state_post);
//初始化纠正后的矩阵
//开始卡尔曼学习
while(1)
{
//估计点的位置
const CvMat *y_k=cvKalmanPredict(kalman,0);
//产生测量值
cvRandSetRange(&rng,0,sqrt(kalman->measurement_matrix->data.fl[0]),0);
//这个数大概在0到0.6之间
cvRand(&rng,z_k);//这里是误差v_k...原书作者真是骚气
cvMatMulAdd(kalman->measurement_matrix,x_k,z_k,z_k);
//将src1*src2+src3=dst4
//z_k=H*x_k+v_k
cvZero(img);
//画画
cvZero(img);
//观测值,标记为红色
cvCircle(img,phi2xy(z_k),6,cvScalar(0,0,255));
//预测值 //标记为蓝色
cvCircle(img,phi2xy(y_k),4,cvScalar(255,0,0));
//纠正值(前一次的) //标记为绿色
cvCircle(img,phi2xy(x_k),8,cvScalar(0,255,0));
cvShowImage("Boss Kalman",img);
//下面开始调整卡尔曼滤波
//只需要传入观测值即可
cvKalmanCorrect(kalman,z_k);
//运用传递矩阵F算出下次的x_k的值
cvRandSetRange(&rng,0,sqrt(kalman->process_noise_cov->data.fl[0]),0);
cvRand(&rng,w_k);
//w_k大概在0到10的-3次方之间
cvMatMulAdd(kalman->transition_matrix,x_k,w_k,x_k);
//就是那个著名的公式:,x_k^-=Fx_(k-1)+Bu_(k-1)+w_k
//即F*x_k+w_k=x_k
if(cvWaitKey(40)==27)
break;
}
return 0;
}
//程序开始后我们会看到绿圈渐渐趋于稳定,并且绿圈总是滞后与篮圈一点,因为是上一次的啦,不过它们都渐渐趋于稳定