-
Notifications
You must be signed in to change notification settings - Fork 0
/
lkdemo.py
290 lines (232 loc) · 8.84 KB
/
lkdemo.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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
#! /usr/bin/env python
print "OpenCV Python version of lkdemo"
import sys
import time
import sched
import Queue
from threading import Timer
# import the necessary things for OpenCV
from opencv import cv
from opencv import highgui
#############################################################################
# some "constants"
win_size = 10
MAX_COUNT = 500
#############################################################################
# some "global" variables
image = None
pt = None
add_remove_pt = False
flags = 0
night_mode = False
need_to_init = False
# the default parameters
quality = 0.01
min_distance = 10
tevent = Queue.Queue()
#############################################################################
# the mouse callback
# the callback on the trackbar
def on_mouse (event, x, y, flags, param):
# we will use the global pt and add_remove_pt
global pt
global add_remove_pt
if image is None:
# not initialized, so skip
return
if event == highgui.CV_EVENT_LBUTTONDOWN:
# user has click, so memorize it
pt = cv.cvPoint (x, y)
add_remove_pt = True
def reinit():
need_to_init = True
tevent.put(s1.enter(1,1,reinit,()))
print 'starting timer'
def stop():
while not s1.empty:
s1.cancel(tevent.get())
print 'stopping timer'
# the timer that triggers feature refresh events
#t = Timer(1.0,reinit)
s1 = sched.scheduler(time.time,time.sleep)
tevent.put(s1.enter(1,1,reinit,()))
#############################################################################
# so, here is the main part of the program
if __name__ == '__main__':
try:
# try to get the device number from the command line
device = int (sys.argv [1])
# got it ! so remove it from the arguments
del sys.argv [1]
except (IndexError, ValueError):
# no device number on the command line, assume we want the 1st device
device = 0
if len (sys.argv) == 1:
# no argument on the command line, try to use the camera
capture = highgui.cvCreateCameraCapture (device)
else:
# we have an argument on the command line,
# we can assume this is a file name, so open it
capture = highgui.cvCreateFileCapture (sys.argv [1])
# check that capture device is OK
if not capture:
print "Error opening capture device"
sys.exit (1)
# display a small howto use it
print "Hot keys: \n" \
"\tESC - quit the program\n" \
"\tr - auto-initialize tracking\n" \
"\tc - delete all the points\n" \
"\tn - switch the \"night\" mode on/off\n" \
"To add/remove a feature point click it\n"
# first, create the necessary windows
highgui.cvNamedWindow ('LkDemo', highgui.CV_WINDOW_AUTOSIZE)
# register the mouse callback
highgui.cvSetMouseCallback ('LkDemo', on_mouse, None)
# run reinit every 1 second.
# s1.run()
t2 = time.time()
while 1:
# do forever
#time stamp for current frame
t1 = time.time()
#reinit features every 5 seconds
if(t1 - t2 > 5):
need_to_init = True
t2 = t1
# 1. capture the current image
frame = highgui.cvQueryFrame (capture)
if frame is None:
# no image captured... end the processing
break
if image is None:
# create the images we need
image = cv.cvCreateImage (cv.cvGetSize (frame), 8, 3)
grey = cv.cvCreateImage (cv.cvGetSize (frame), 8, 1)
prev_grey = cv.cvCreateImage (cv.cvGetSize (frame), 8, 1)
pyramid = cv.cvCreateImage (cv.cvGetSize (frame), 8, 1)
prev_pyramid = cv.cvCreateImage (cv.cvGetSize (frame), 8, 1)
eig = cv.cvCreateImage (cv.cvGetSize (frame), cv.IPL_DEPTH_32F, 1)
temp = cv.cvCreateImage (cv.cvGetSize (frame), cv.IPL_DEPTH_32F, 1)
points = [[], []]
# copy the frame, so we can draw on it
cv.cvCopy (frame, image)
# create a grey version of the image
cv.cvCvtColor (image, grey, cv.CV_BGR2GRAY)
if night_mode:
# night mode: only display the points
cv.cvSetZero (image)
if need_to_init:
# we want to search all the good points
# create the wanted images
# search the good points
points [1] = cv.cvGoodFeaturesToTrack (
grey, eig, temp,
MAX_COUNT,
quality, min_distance, None, 3, 0, 0.04)
# refine the corner locations
cv.cvFindCornerSubPix (
grey,
points [1],
cv.cvSize (win_size, win_size), cv.cvSize (-1, -1),
cv.cvTermCriteria (cv.CV_TERMCRIT_ITER | cv.CV_TERMCRIT_EPS,
20, 0.03))
elif len (points [0]) > 0:
# we have points, so display them
# calculate the optical flow
# documentation is in the opencv reference manual
# points[0] --> features in previous frame
# points[1] --> features in current frame
[points [1], status], tracking_error = cv.cvCalcOpticalFlowPyrLK (
prev_grey, grey, prev_pyramid, pyramid,
points [0], #previous_features
len (points [0]),
(win_size, win_size),
3,
len (points [0]),
None,
cv.cvTermCriteria (cv.CV_TERMCRIT_ITER|cv.CV_TERMCRIT_EPS,
20, 0.03), #criteria
flags)
# initializations
point_counter = -1
new_points = []
velocities = [[],[]]
old_points = points[0]
for the_point in points[1]:
# go through all the points
# increment the counter
point_counter += 1
if add_remove_pt:
# we have a point to add, so see if it is close to
# another one. If yes, don't use it
dx = pt.x - the_point.x
dy = pt.y - the_point.y
if dx * dx + dy * dy <= 25:
# too close
add_remove_pt = 0
continue
if not status [point_counter]:
# we will disable this point
continue
# this point is a correct point
new_points.append (the_point)
# draw the current point
cv.cvCircle (image,
cv.cvPointFrom32f(the_point),
3, cv.cvScalar (0, 255, 0, 0),
-1, 8, 0)
# draw the flow vector
if status[point_counter]:
dx1 = old_points[point_counter].x - the_point.x
dy1 = old_points[point_counter].y - the_point.y
if dx1 * dx1 + dy1 * dy1 <= 500:
cv.cvLine(image,
cv.cvPointFrom32f(old_points[point_counter]),
cv.cvPointFrom32f(the_point),
cv.cvScalar(0,255,0,0), 2)
#print 'velocity: ',dx1/(time.time()-t1),dy1/(time.time()-t1)
velocities[0].append(dx1/(time.time()-t1))
velocities[1].append(dy1/(time.time()-t1))
# set back the points we keep
points [1] = new_points
if len(velocities[0]) != 0 and len(velocities[1]) != 0:
vavgx = sum(velocities[0])/len(velocities[0])
vavgy = sum(velocities[1])/len(velocities[1])
else:
vavgx = 0
vavgy = 0
print "velocity",vavgx,vavgy
if add_remove_pt:
# we want to add a point
points [1].append (cv.cvPointTo32f (pt))
# refine the corner locations
points [1][-1] = cv.cvFindCornerSubPix (
grey,
[points [1][-1]],
cv.cvSize (win_size, win_size), cv.cvSize (-1, -1),
cv.cvTermCriteria (cv.CV_TERMCRIT_ITER | cv.CV_TERMCRIT_EPS,
20, 0.03))[0]
# we are no more in "add_remove_pt" mode
add_remove_pt = False
# swapping
prev_grey, grey = grey, prev_grey
prev_pyramid, pyramid = pyramid, prev_pyramid
points [0], points [1] = points [1], points [0]
need_to_init = False
# we can now display the image
highgui.cvShowImage ('LkDemo', image)
# handle events
c = highgui.cvWaitKey (10)
if c == '\x1b':
# user has press the ESC key, so exit
# stop()
exit()
break
# processing depending on the character
if c in ['r', 'R']:
need_to_init = True
elif c in ['c', 'C']:
points = [[], []]
elif c in ['n', 'N']:
night_mode = not night_mode