目录
一、Kalman
二、流程
三、代码
3.1 meanshift+kalman实现
在上面的跟踪中,meanshift和camshift链接。我们使用的都是Meanshift或者是基于Meanshift的Camshift来进行的跟踪,这里我们还可以对其进行改良:引入卡尔曼滤波的概念。
卡尔曼滤波的概念较为复杂,这里我们可以理解为:从一个含有噪音的输入中,得出一个具有统计意义上较为良好的估计值。
我们举个简单的例子,比如我现在有一个物体,正在以1m/s的速度(过去测量得到的值)离我远去,当前它离我1m远,因为我们知道他正在以1m/s的速度远离我,所以下一秒我就能估计出它离我2m远,这个是显然的。但是如果这个物体撞到了什么东西后,速度改变了,我们就会根据它实际位置上的值(含有噪音的模糊输入)来矫正我们的猜测。 卡尔曼滤波一般我们设置为4个参数,其中两个是可以直接得到的。举个例子,我们使用函数来创建一个卡尔曼滤波器:
klm=cv2.KalmanFilter(4,2)
这里的4表示的是有四个参数分别是(x,y,dx,dy),前两个是我们输入进去的参数,物体跟踪里面我们假定为我们跟踪物体的中心的坐标,dx和dy表示的是物体移动的速度,为观测量,不能直接得到,所以其实我们能直接输入进去的参数就只有坐标,x和y两个值,所以初始化的时候4后面跟一个2,所以就是(4,2) 然后我们需要设置卡尔曼滤波器的几个矩阵:
klm.measurementMatrix = np.array([[1,0,0,0],[0,1,0,0]],np.float32)
klm.transitionMatrix = np.array([[1,0,1,0],[0,1,0,1],[0,0,1,0],[0,0,0,1]],np.float32)
klm.processNoiseCov = np.array([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]],np.float32)
参数:
现在我们对上文优化的基础上,再加入卡尔曼滤波,我们把矩形框的中间位置作为输入,加载到卡尔曼滤波器中,预测出现在物体的位置后,以预测位置为圆心画一个圆,示例代码如下所示:
import cv2
import numpy as np
def center(points):
x = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4
y = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4
return np.array([np.float32(x), np.float32(y)], np.float32)
cap = cv2.VideoCapture('E:\Python-Code/videodataset/enn.mp4')
ret, frame = cap.read()
# 我这里画面太大了所以缩小点
# frame = cv2.resize(frame, None, None, fx=1 / 2, fy=1 / 2, interpolation=cv2.INTER_CUBIC)
# 跟踪框
track_window = cv2.selectROI('img', frame)
# 获得绿色的直方图
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, np.array((35, 43, 46)), np.array((77, 255, 255)))
hist = cv2.calcHist([hsv], [0], mask, [181], [0, 180])
cv2.normalize(hist, hist, 0, 255, cv2.NORM_MINMAX)
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
# 设置卡尔曼滤波器
klm = cv2.KalmanFilter(4, 2)
klm.measurementMatrix = np.array([[1, 0, 0, 0], [0, 1, 0, 0]], np.float32)
klm.transitionMatrix = np.array([[1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]], np.float32)
klm.processNoiseCov = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], np.float32)
while 1:
ret, frame = cap.read()
# frame = cv2.resize(frame, None, None, fx=1 / 2, fy=1 / 2, interpolation=cv2.INTER_CUBIC)
if ret == True:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
dst = cv2.calcBackProject([hsv], [0], hist, [0, 180], 1)
ret, track_window = cv2.meanShift(dst, track_window, term_crit)
x, y, w, h = track_window
# 获得中间坐标
cent = center([[x, y], [x + w, y], [x, y + h], [x + w, y + h]])
# 修正参数
klm.correct(cent)
# 预测
c = klm.predict()
# 画出预测位置
cv2.circle(frame, (int(c[0]), int(c[1])), 30, (255, 255, 0), -1)
# 画出矩形框
img = cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
(x, y) = img.shape[:2]
cv2.imshow('img', img)
if cv2.waitKey(1) == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()