-
Notifications
You must be signed in to change notification settings - Fork 98
/
track_camshift.py
190 lines (149 loc) · 6.24 KB
/
track_camshift.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
'''
基于卡尔曼滤波的Cam-Shift对象跟踪
'''
import numpy as np
import cv2
keep_processing = True
camera_to_use = 0;
selection_in_progress = False # 支持感兴趣区域选择
# 使用鼠标来选择区域
boxes = []
current_mouse_position = np.ones(2, dtype=np.int32)
# 使用鼠标绘制矩形框选择区域
def on_mouse(event, x, y, flags, params):
global boxes
global selection_in_progress
current_mouse_position[0] = x
current_mouse_position[1] = y
# 左击鼠标(按下)
if event == cv2.EVENT_LBUTTONDOWN:
boxes = []
sbox = [x, y]
selection_in_progress = True
boxes.append(sbox)
elif event == cv2.EVENT_LBUTTONUP:
ebox = [x, y]
selection_in_progress = False
boxes.append(ebox)
# 返回所选择矩形框的中心点
def center(points):
x = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4.0
y = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4.0
return np.array([np.float32(x), np.float32(y)], np.float32)
# 用作call-back当每次轨迹条移动时,可以当做什么也不做
def nothing(x):
pass
# 定义视频捕捉对象
cap = cv2.VideoCapture(0)
# 定义展示的窗口名
windowName = "Kalman Object Tracking"
windowName2 = "Hue histogram back projection"
windowNameSelection = "initial selected region"
# 初始化卡尔曼滤波器所有参数
kalman = cv2.KalmanFilter(4, 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)
measurement = np.array((2, 1), np.float32)
prediction = np.zeros((2, 1), np.float32)
# 打开视频
file = "test_videos/street.mp4"
cap = cv2.VideoCapture(file)
# 创建窗口
cv2.namedWindow(windowName, cv2.WINDOW_NORMAL)
cv2.namedWindow(windowName2, cv2.WINDOW_NORMAL)
cv2.namedWindow(windowNameSelection, cv2.WINDOW_NORMAL)
# 设置HSV选择阈值的滑块
s_lower = 60
cv2.createTrackbar("s lower", windowName2, s_lower, 255, nothing)
s_upper = 255;
cv2.createTrackbar("s upper", windowName2, s_upper, 255, nothing)
v_lower = 32;
cv2.createTrackbar("v lower", windowName2, v_lower, 255, nothing)
v_upper = 255;
cv2.createTrackbar("v upper", windowName2, v_upper, 255, nothing)
# 设置一个鼠标回调函数
cv2.setMouseCallback(windowName, on_mouse, 0)
cropped = False
# 设置迭代次数,或者迭代10次或者至少移动1次
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
while keep_processing:
#视频成功打开
if cap.isOpened:
ret,frame=cap.read()
#开始一个计时器(测试处理以及展示所花时间)
start_timer=cv2.getTickCount()
#从滑动条中获得参数
s_lower = cv2.getTrackbarPos("s lower", windowName2);
s_upper = cv2.getTrackbarPos("s upper", windowName2);
v_lower = cv2.getTrackbarPos("v lower", windowName2);
v_upper = cv2.getTrackbarPos("v upper", windowName2);
#通过鼠标选择区域并且进行展示
if len(boxes)>1:
crop=frame[boxes[0][1]:boxes[1][1],boxes[0][0]:boxes[1][0]].copy()#获得选择的区域图
h,w,c=crop.shape
if h>0 and w>0:
cropped=True
#将选择区域转换成HSV形式
hsv_crop=cv2.cvtColor(crop,cv2.COLOR_BGR2HSV)
#选择所有色彩(0->180)
mask=cv2.inRange(hsv_crop,np.array((0.,float(s_lower),float(v_lower))),np.array((180.,
float(s_upper),float(v_upper))))
#构造一个色调和饱和度直方图并将其归一化
crop_hist=cv2.calcHist([hsv_crop],[0,1],mask,[180,255],[0,180,0,255])
cv2.normalize(crop_hist,crop_hist,0,255,cv2.NORM_MINMAX)
#设置对象的初始位置
track_window=(boxes[0][0],boxes[0][1],boxes[1][0]-boxes[0][0],boxes[1][1]-boxes[0][1])
cv2.imshow(windowNameSelection,crop)
#重置盒子列表
boxes=[]
#选择区域进行展示,对别选择的对象做一个绿色的边框
if selection_in_progress:
top_left=(boxes[0][0],boxes[0][1])
bottom_right=(current_mouse_position[0],current_mouse_position[1])
cv2.rectangle(frame,top_left,bottom_right,(0,0,255),2)
#如果已经选择区域
if cropped:
#转化整个输入图片为HSV形式
img_hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
#基于色调和饱和度的直方图反投影
img_bproject=cv2.calcBackProject([img_hsv],[0,1],crop_hist,[0,180,0,255],1)
cv2.imshow(windowName2,img_bproject)
#利用camshift来预测新位置
ret,track_window=cv2.CamShift(img_bproject,track_window,term_crit)
#在图上绘制观测对象
x,y,w,h=track_window
frame=cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
#提取观察对象的中心点
pts=cv2.boxPoints(ret)
pts=np.int0(pts)
#使用卡尔曼滤波器
kalman.correct(center(pts))
#得到新的卡尔曼滤波器预测对象
prediction=kalman.predict()
#在图上进行绘制
frame=cv2.rectangle(frame,(prediction[0]-(0.5*w),prediction[1]-(0.5*h)),(prediction[0]+(0.5*w),
prediction[1]+(0.5*h)),(0,255,0),2)
else:
#在选择我们所使用的选择区域前
img_hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
mask=cv2.inRange(img_hsv,np.array((0.,float(s_lower),float(v_lower))),np.array((180.,
float(s_upper),float(v_upper))))
cv2.imshow(windowName2,mask)
#展示图片
cv2.imshow(windowName,frame)
#停止加时器
stop_timer=((cv2.getTickCount()-start_timer)/cv2.getTickFrequency())*1000
# key=cv2.waitKey(max(2,40-int(math.ceil(stop_timer))))&0xFF
key=cv2.waitKey(200)&0xFF
if key==27:
keep_processing=False
cv2.destroyAllWindows()
cap.release()