comparison python/moving.py @ 708:a37c565f4b68

merged dev
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Wed, 22 Jul 2015 14:17:44 -0400
parents 463150a8e129
children e14e2101a5a9
comparison
equal deleted inserted replaced
707:7efa36b9bcfd 708:a37c565f4b68
3 3
4 import utils, cvutils 4 import utils, cvutils
5 from base import VideoFilenameAddable 5 from base import VideoFilenameAddable
6 6
7 from math import sqrt, atan2, cos, sin 7 from math import sqrt, atan2, cos, sin
8 from numpy import median, array, zeros, hypot, NaN, std 8 from numpy import median, array, zeros, hypot, NaN, std, floor, float32
9 from matplotlib.pyplot import plot 9 from matplotlib.pyplot import plot
10 from scipy.stats import scoreatpercentile 10 from scipy.stats import scoreatpercentile
11 from scipy.spatial.distance import cdist 11 from scipy.spatial.distance import cdist
12 12
13 try: 13 try:
76 elif self.last < interval2.first: 76 elif self.last < interval2.first:
77 return interval2.first - self.last 77 return interval2.first - self.last
78 else: 78 else:
79 return None 79 return None
80 80
81
82 def unionIntervals(intervals): 81 def unionIntervals(intervals):
83 'returns the smallest interval containing all intervals' 82 'returns the smallest interval containing all intervals'
84 inter = intervals[0] 83 inter = intervals[0]
85 for i in intervals[1:]: 84 for i in intervals[1:]:
86 inter = Interval.union(inter, i) 85 inter = Interval.union(inter, i)
121 120
122 def length(self): 121 def length(self):
123 '''Returns the length of the interval''' 122 '''Returns the length of the interval'''
124 return float(max(0,self.last-self.first+1)) 123 return float(max(0,self.last-self.first+1))
125 124
125 def __len__(self):
126 return self.length()
127
126 # class BoundingPolygon: 128 # class BoundingPolygon:
127 # '''Class for a polygon bounding a set of points 129 # '''Class for a polygon bounding a set of points
128 # with methods to create intersection, unions... 130 # with methods to create intersection, unions...
129 # ''' 131 # '''
130 # We will use the polygon class of Shapely 132 # We will use the polygon class of Shapely
140 self.num = num 142 self.num = num
141 self.timeInterval = timeInterval 143 self.timeInterval = timeInterval
142 self.boundingPolygon = boundingPolygon 144 self.boundingPolygon = boundingPolygon
143 145
144 def empty(self): 146 def empty(self):
145 return self.timeInterval.empty() or not self.boudingPolygon 147 return self.timeInterval.empty()# or not self.boudingPolygon
146 148
147 def getNum(self): 149 def getNum(self):
148 return self.num 150 return self.num
151
152 def __len__(self):
153 return self.timeInterval.length()
154
155 def length(self):
156 return self.timeInterval.length()
149 157
150 def getFirstInstant(self): 158 def getFirstInstant(self):
151 return self.timeInterval.first 159 return self.timeInterval.first
152 160
153 def getLastInstant(self): 161 def getLastInstant(self):
188 elif i == 1: 196 elif i == 1:
189 return self.y 197 return self.y
190 else: 198 else:
191 raise IndexError() 199 raise IndexError()
192 200
193 def orthogonal(self): 201 def orthogonal(self, clockwise = True):
194 return Point(self.y, -self.x) 202 'Returns the orthogonal vector'
203 if clockwise:
204 return Point(self.y, -self.x)
205 else:
206 return Point(-self.y, self.x)
195 207
196 def multiply(self, alpha): 208 def multiply(self, alpha):
197 'Warning, returns a new Point' 209 'Warning, returns a new Point'
198 return Point(self.x*alpha, self.y*alpha) 210 return Point(self.x*alpha, self.y*alpha)
199 211
1053 return obj 1065 return obj
1054 else: 1066 else:
1055 print 'The object does not exist at '+str(inter) 1067 print 'The object does not exist at '+str(inter)
1056 return None 1068 return None
1057 1069
1058 def length(self):
1059 return self.timeInterval.length()
1060
1061 def getPositions(self): 1070 def getPositions(self):
1062 return self.positions 1071 return self.positions
1063 1072
1064 def getVelocities(self): 1073 def getVelocities(self):
1065 return self.velocities 1074 return self.velocities
1127 return featureNumbers 1136 return featureNumbers
1128 else: 1137 else:
1129 print('Object {} has no features loaded.'.format(self.getNum())) 1138 print('Object {} has no features loaded.'.format(self.getNum()))
1130 return None 1139 return None
1131 1140
1132 def getSpeeds(self): 1141 def getSpeeds(self, nInstantsIgnoredAtEnds = 0):
1133 return self.getVelocities().norm() 1142 speeds = self.getVelocities().norm()
1143 if nInstantsIgnoredAtEnds > 0:
1144 n = min(nInstantsIgnoredAtEnds, int(floor(self.length()/2.)))
1145 return speeds[n:-n]
1146 else:
1147 return speeds
1134 1148
1135 def getSpeedIndicator(self): 1149 def getSpeedIndicator(self):
1136 from indicators import SeverityIndicator 1150 from indicators import SeverityIndicator
1137 return SeverityIndicator('Speed', {t:self.getVelocityAtInstant(t).norm2() for t in self.getTimeInterval()}) 1151 return SeverityIndicator('Speed', {t:self.getVelocityAtInstant(t).norm2() for t in self.getTimeInterval()})
1138 1152
1344 relativePositions[(j,i)] = -relativePositions[(i,j)] 1358 relativePositions[(j,i)] = -relativePositions[(i,j)]
1345 1359
1346 ### 1360 ###
1347 # User Type Classification 1361 # User Type Classification
1348 ### 1362 ###
1349 def classifyUserTypeSpeedMotorized(self, threshold, aggregationFunc = median, ignoreNInstantsAtEnds = 0): 1363 def classifyUserTypeSpeedMotorized(self, threshold, aggregationFunc = median, nInstantsIgnoredAtEnds = 0):
1350 '''Classifies slow and fast road users 1364 '''Classifies slow and fast road users
1351 slow: non-motorized -> pedestrians 1365 slow: non-motorized -> pedestrians
1352 fast: motorized -> cars 1366 fast: motorized -> cars
1353 1367
1354 aggregationFunc can be any function that can be applied to a vector of speeds, including percentile: 1368 aggregationFunc can be any function that can be applied to a vector of speeds, including percentile:
1355 aggregationFunc = lambda x: percentile(x, percentileFactor) # where percentileFactor is 85 for 85th percentile''' 1369 aggregationFunc = lambda x: percentile(x, percentileFactor) # where percentileFactor is 85 for 85th percentile'''
1356 if ignoreNInstantsAtEnds > 0: 1370 speeds = self.getSpeeds(nInstantsIgnoredAtEnds)
1357 speeds = self.getSpeeds()[ignoreNInstantsAtEnds:-ignoreNInstantsAtEnds]
1358 else:
1359 speeds = self.getSpeeds()
1360 if aggregationFunc(speeds) >= threshold: 1371 if aggregationFunc(speeds) >= threshold:
1361 self.setUserType(userType2Num['car']) 1372 self.setUserType(userType2Num['car'])
1362 else: 1373 else:
1363 self.setUserType(userType2Num['pedestrian']) 1374 self.setUserType(userType2Num['pedestrian'])
1364 1375
1365 def classifyUserTypeSpeed(self, speedProbabilities, aggregationFunc = median): 1376 def classifyUserTypeSpeed(self, speedProbabilities, aggregationFunc = median, nInstantsIgnoredAtEnds = 0):
1366 '''Classifies road user per road user type 1377 '''Classifies road user per road user type
1367 speedProbabilities are functions return P(speed|class) 1378 speedProbabilities are functions return P(speed|class)
1368 in a dictionary indexed by user type names 1379 in a dictionary indexed by user type names
1369 Returns probabilities for each class 1380 Returns probabilities for each class
1370 1381
1373 if abs(x-mu) < sigma: 1384 if abs(x-mu) < sigma:
1374 return 1 1385 return 1
1375 else: 1386 else:
1376 return x''' 1387 return x'''
1377 if not hasattr(self, 'aggregatedSpeed'): 1388 if not hasattr(self, 'aggregatedSpeed'):
1378 self.aggregatedSpeed = aggregationFunc(self.getSpeeds()) 1389 self.aggregatedSpeed = aggregationFunc(self.getSpeeds(nInstantsIgnoredAtEnds))
1379 userTypeProbabilities = {} 1390 userTypeProbabilities = {}
1380 for userTypename in speedProbabilities: 1391 for userTypename in speedProbabilities:
1381 userTypeProbabilities[userType2Num[userTypename]] = speedProbabilities[userTypename](self.aggregatedSpeed) 1392 userTypeProbabilities[userType2Num[userTypename]] = speedProbabilities[userTypename](self.aggregatedSpeed)
1382 self.setUserType(utils.argmaxDict(userTypeProbabilities)) 1393 self.setUserType(utils.argmaxDict(userTypeProbabilities))
1383 return userTypeProbabilities 1394 return userTypeProbabilities
1384 1395
1385 def initClassifyUserTypeHoGSVM(self, aggregationFunc = median): 1396 def initClassifyUserTypeHoGSVM(self, aggregationFunc, pedBikeCarSVM, bikeCarSVM = None, pedBikeSpeedTreshold = float('Inf'), bikeCarSpeedThreshold = float('Inf'), nInstantsIgnoredAtEnds = 0):
1386 '''Initializes the data structures for classification 1397 '''Initializes the data structures for classification
1387 1398
1388 TODO? compute speed for longest feature? 1399 TODO? compute speed for longest feature?'''
1389 Skip beginning and end of feature for speed? Offer options instead of median''' 1400 self.aggregatedSpeed = aggregationFunc(self.getSpeeds(nInstantsIgnoredAtEnds))
1390 self.aggregatedSpeed = aggregationFunc(self.getSpeeds()) 1401 if self.aggregatedSpeed < pedBikeSpeedTreshold or bikeCarSVM is None:
1402 self.appearanceClassifier = pedBikeCarSVM
1403 elif self.aggregatedSpeed < bikeCarSpeedThreshold:
1404 self.appearanceClassifier = bikeCarSVM
1405 else:
1406 class CarClassifier:
1407 def predict(self, hog):
1408 return userType2Num['car']
1409 self.appearanceClassifier = CarClassifier()
1410
1391 self.userTypes = {} 1411 self.userTypes = {}
1392 1412
1393 def classifyUserTypeHoGSVMAtInstant(self, img, pedBikeCarSVM, instant, homography, width, height, bikeCarSVM = None, pedBikeSpeedTreshold = float('Inf'), bikeCarSpeedThreshold = float('Inf'), px = 0.2, py = 0.2, pixelThreshold = 800): 1413 def classifyUserTypeHoGSVMAtInstant(self, img, instant, homography, width, height, px = 0.2, py = 0.2, minNPixels = 800):
1394 '''Extract the image box around the object and 1414 '''Extract the image box around the object and
1395 applies the SVM model on it''' 1415 applies the SVM model on it'''
1396 croppedImg, yCropMin, yCropMax, xCropMin, xCropMax = imageBox(img, self, instant, homography, width, height, px, py, pixelThreshold) 1416 croppedImg, yCropMin, yCropMax, xCropMin, xCropMax = cvutils.imageBox(img, self, instant, homography, width, height, px, py, minNPixels)
1397 if len(croppedImg) > 0: # != [] 1417 if croppedImg is not None and len(croppedImg) > 0:
1398 hog = array([cvutils.HOG(croppedImg)], dtype = np.float32) 1418 hog = cvutils.HOG(croppedImg)#HOG(image, rescaleSize = (64, 64), orientations=9, pixelsPerCell=(8, 8), cellsPerBlock=(2, 2), visualize=False, normalize=False)
1399 if self.aggregatedSpeed < pedBikeSpeedTreshold or bikeCarSVM is None: 1419 self.userTypes[instant] = int(self.appearanceClassifier.predict(hog))
1400 self.userTypes[instant] = int(pedBikeCarSVM.predict(hog))
1401 elif self.aggregatedSpeed < bikeCarSpeedTreshold:
1402 self.userTypes[instant] = int(bikeCarSVM.predict(hog))
1403 else:
1404 self.userTypes[instant] = userType2Num['car']
1405 else: 1420 else:
1406 self.userTypes[instant] = userType2Num['unknown'] 1421 self.userTypes[instant] = userType2Num['unknown']
1407 1422
1408 def classifyUserTypeHoGSVM(self, images, pedBikeCarSVM, homography, width, height, bikeCarSVM = None, pedBikeSpeedTreshold = float('Inf'), bikeCarSpeedThreshold = float('Inf'), speedProbabilities = None, aggregationFunc = median, px = 0.2, py = 0.2, pixelThreshold = 800): 1423 def classifyUserTypeHoGSVM(self, pedBikeCarSVM = None, width = 0, height = 0, homography = None, images = None, bikeCarSVM = None, pedBikeSpeedTreshold = float('Inf'), bikeCarSpeedThreshold = float('Inf'), minSpeedEquiprobable = -1, speedProbabilities = None, aggregationFunc = median, nInstantsIgnoredAtEnds = 0, px = 0.2, py = 0.2, minNPixels = 800):
1409 '''Agregates SVM detections in each image and returns probability 1424 '''Agregates SVM detections in each image and returns probability
1410 (proportion of instants with classification in each category) 1425 (proportion of instants with classification in each category)
1411 1426
1412 iamges is a dictionary of images indexed by instant 1427 images is a dictionary of images indexed by instant
1413 With default parameters, the general (ped-bike-car) classifier will be used 1428 With default parameters, the general (ped-bike-car) classifier will be used
1414 TODO? consider all categories?''' 1429
1415 if not hasattr(self, aggregatedSpeed) or not hasattr(self, userTypes): 1430 Considered categories are the keys of speedProbabilities'''
1431 if not hasattr(self, 'aggregatedSpeed') or not hasattr(self, 'userTypes'):
1416 print('Initilize the data structures for classification by HoG-SVM') 1432 print('Initilize the data structures for classification by HoG-SVM')
1417 self.initClassifyUserTypeHoGSVM(aggregationFunc) 1433 self.initClassifyUserTypeHoGSVM(aggregationFunc, pedBikeCarSVM, bikeCarSVM, pedBikeSpeedTreshold, bikeCarSpeedThreshold, nInstantsIgnoredAtEnds)
1418 1434
1419 if len(self.userTypes) != self.length(): # if classification has not been done previously 1435 if len(self.userTypes) != self.length() and images is not None: # if classification has not been done previously
1420 for t in self.getTimeInterval(): 1436 for t in self.getTimeInterval():
1421 if t not in self.userTypes: 1437 if t not in self.userTypes:
1422 self.classifyUserTypeHoGSVMAtInstant(images[t], pedBikeCarSVM, t, homography, width, height, bikeCarSVM, pedBikeSpeedTreshold, bikeCarSpeedThreshold, px, py, pixelThreshold) 1438 self.classifyUserTypeHoGSVMAtInstant(images[t], t, homography, width, height, px, py, minNPixels)
1423 # compute P(Speed|Class) 1439 # compute P(Speed|Class)
1424 if speedProbabilities is None: # equiprobable information from speed 1440 if speedProbabilities is None or self.aggregatedSpeed < minSpeedEquiprobable: # equiprobable information from speed
1425 userTypeProbabilities = {userType2Num['car']: 1., userType2Num['pedestrian']: 1., userType2Num['bicycle']: 1.} 1441 userTypeProbabilities = {userType2Num['car']: 1., userType2Num['pedestrian']: 1., userType2Num['bicycle']: 1.}
1426 else: 1442 else:
1427 userTypeProbabilities = {userType2Num[userTypename]: speedProbabilities[userTypename](self.aggregatedSpeed) for userTypename in speedProbabilities} 1443 userTypeProbabilities = {userType2Num[userTypename]: speedProbabilities[userTypename](self.aggregatedSpeed) for userTypename in speedProbabilities}
1428 # result is P(Class|Appearance) x P(Speed|Class) 1444 # result is P(Class|Appearance) x P(Speed|Class)
1429 nInstantsUserType = {userType2Num[userTypename]: 0 for userTypename in userTypeProbabilities}# number of instants the object is classified as userTypename 1445 nInstantsUserType = {userTypeNum: 0 for userTypeNum in userTypeProbabilities}# number of instants the object is classified as userTypename
1430 for t in self.userTypes: 1446 for t in self.userTypes:
1431 nInstantsUserType[self.userTypes[t]] += 1 1447 nInstantsUserType[self.userTypes[t]] = nInstantsUserType.get(self.userTypes[t], 0) + 1
1432 for userTypename in userTypeProbabilities: 1448 for userTypeNum in userTypeProbabilities:
1433 userTypeProbabilities[userTypename] *= nInstantsUserType[userTypename] 1449 userTypeProbabilities[userTypeNum] *= nInstantsUserType[userTypeNum]
1434 # class is the user type that maximizes usertype probabilities 1450 # class is the user type that maximizes usertype probabilities
1435 self.setUserType(utils.argmaxDict(userTypeProbabilities)) 1451 self.setUserType(utils.argmaxDict(userTypeProbabilities))
1436 1452
1437 def classifyUserTypeArea(self, areas, homography): 1453 def classifyUserTypeArea(self, areas, homography):
1438 '''Classifies the object based on its location (projected to image space) 1454 '''Classifies the object based on its location (projected to image space)