卡尔曼是匈牙利数学家,Kalman滤波器源于其博士毕业了论文和1960年发表的论文《A New Approach to Linear Filtering and Prediction Problems》
(线性滤波与预测问题的新方法)。
论文地址
卡尔曼滤波不要求信号和噪声都是平稳过程的假设条件。对于每个时刻的系统扰动和观测误差(即噪声),只要对它们的统计性质作某些适当的假定,通过对含有噪声的观测信号进行处理,就能在平均的意义上,求得误差为最小的真实信号的估计值。
因此,自从卡尔曼滤波理论问世以来,在通信系统、电力系统、航空航天、环境污染控制、工业控制、雷达信号处理等许多部门都得到了应用,取得了许多成功应用的成果。卡尔曼滤波器会对含有噪声的输入数据流(比如计算机视觉中的视频输入)进行递归操作,并产生底层系统状态(比如视频中的位置)在统计意义上的最优估计。
卡尔曼滤波算法分为两个阶段:
预测阶段:卡尔曼滤波器使用由当前点计算的协方差来估计目标的新位置;
更新阶段:卡尔曼滤波器记录目标的位置,并为下一次循环计算修正协方差。
整个卡尔曼滤波的过程就是个递推计算的过程,不断的“预测–更新–预测–更新……”
import cv2
import numpy as np
# 创建一个空帧,定义(700, 700, 3)画图区域
frame = np.zeros((700, 700, 3), np.uint8)
# 初始化测量坐标和鼠标运动预测的数组
last_measurement = current_measurement = np.array((2, 1), np.float32)
last_prediction = current_prediction = np.zeros((2, 1), np.float32)
# 定义鼠标回调函数,用来绘制跟踪结果
def mousemove(event, x, y, s, p):
global frame, current_measurement, measurements, last_measurement, current_prediction, last_prediction
last_prediction = current_prediction # 把当前预测存储为上一次预测
last_measurement = current_measurement # 把当前测量存储为上一次测量
current_measurement = np.array([[np.float32(x)], [np.float32(y)]]) # 当前测量
kalman.correct(current_measurement) # 用当前测量来校正卡尔曼滤波器
current_prediction = kalman.predict() # 计算卡尔曼预测值,作为当前预测
lmx, lmy = last_measurement[0], last_measurement[1] # 上一次测量坐标
cmx, cmy = current_measurement[0], current_measurement[1] # 当前测量坐标
lpx, lpy = last_prediction[0], last_prediction[1] # 上一次预测坐标
cpx, cpy = current_prediction[0], current_prediction[1] # 当前预测坐标
# 绘制从上一次测量到当前测量以及从上一次预测到当前预测的两条线
cv2.line(frame, (lmx, lmy), (cmx, cmy), (255, 0, 0)) # 蓝色线为测量值
cv2.line(frame, (lpx, lpy), (cpx, cpy), (255, 0, 255)) # 粉色线为预测值
# 窗口初始化
cv2.namedWindow("kalman_tracker")
# opencv采用setMouseCallback函数处理鼠标事件,具体事件必须由回调(事件)函数的第一个参数来处理,该参数确定触发事件的类型(点击、移动等)
cv2.setMouseCallback("kalman_tracker", mousemove)
kalman = cv2.KalmanFilter(4, 2) # 4:状态数,包括(x,y,dx,dy)坐标及速度(每次移动的距离);2:观测量,能看到的是坐标值
kalman.measurementMatrix = np.array([[1, 0, 0, 0], [0, 1, 0, 0]], np.float32) # 系统测量矩阵
kalman.transitionMatrix = np.array([[1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]], np.float32) # 状态转移矩阵
kalman.processNoiseCov = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], np.float32)*0.03 # 系统过程噪声协方差
while True:
cv2.imshow("kalman_tracker", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
cv2.destroyAllWindows()
一些学习资料:
- 这篇文章对Kalman滤波做了个通俗易懂的介绍:http://www.cnblogs.com/feisky/archive/2009/11/09/1599247.html
- 这篇博客也介绍了鼠标跟踪程序:http://blog.csdn.net/onezeros/article/details/6318944
- 这篇博客对opencv中本身自带的Kalman例子讲解得很清楚,可以学习学习:http://blog.csdn.net/yang_xian521/article/details/7050398
- 这篇博客对卡尔曼滤波相关公式讲的很到位http://lib.csdn.net/article/opencv/29029