Mercurial > hg > nsaunier > traffic-intelligence
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) |
