Mercurial > hg > nsaunier > traffic-intelligence
comparison python/moving.py @ 680:da1352b89d02 dev
classification is working
| author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
|---|---|
| date | Fri, 05 Jun 2015 02:25:30 +0200 |
| parents | ab3fdff42624 |
| children | fbe29be25501 |
comparison
equal
deleted
inserted
replaced
| 678:97c305108460 | 680:da1352b89d02 |
|---|---|
| 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: |
| 75 return self.first - interval2.last | 75 return self.first - interval2.last |
| 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 | |
| 81 | 80 |
| 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:]: |
| 1127 return featureNumbers | 1126 return featureNumbers |
| 1128 else: | 1127 else: |
| 1129 print('Object {} has no features loaded.'.format(self.getNum())) | 1128 print('Object {} has no features loaded.'.format(self.getNum())) |
| 1130 return None | 1129 return None |
| 1131 | 1130 |
| 1132 def getSpeeds(self): | 1131 def getSpeeds(self, nInstantsIgnoredAtEnds = 0): |
| 1133 return self.getVelocities().norm() | 1132 n = min(nInstantsIgnoredAtEnds, int(floor(self.length()/2.))) |
| 1133 return self.getVelocities().norm()[n:-n] | |
| 1134 | 1134 |
| 1135 def getSpeedIndicator(self): | 1135 def getSpeedIndicator(self): |
| 1136 from indicators import SeverityIndicator | 1136 from indicators import SeverityIndicator |
| 1137 return SeverityIndicator('Speed', {t:self.getVelocityAtInstant(t).norm2() for t in self.getTimeInterval()}) | 1137 return SeverityIndicator('Speed', {t:self.getVelocityAtInstant(t).norm2() for t in self.getTimeInterval()}) |
| 1138 | 1138 |
| 1344 relativePositions[(j,i)] = -relativePositions[(i,j)] | 1344 relativePositions[(j,i)] = -relativePositions[(i,j)] |
| 1345 | 1345 |
| 1346 ### | 1346 ### |
| 1347 # User Type Classification | 1347 # User Type Classification |
| 1348 ### | 1348 ### |
| 1349 def classifyUserTypeSpeedMotorized(self, threshold, aggregationFunc = median, ignoreNInstantsAtEnds = 0): | 1349 def classifyUserTypeSpeedMotorized(self, threshold, aggregationFunc = median, nInstantsIgnoredAtEnds = 0): |
| 1350 '''Classifies slow and fast road users | 1350 '''Classifies slow and fast road users |
| 1351 slow: non-motorized -> pedestrians | 1351 slow: non-motorized -> pedestrians |
| 1352 fast: motorized -> cars | 1352 fast: motorized -> cars |
| 1353 | 1353 |
| 1354 aggregationFunc can be any function that can be applied to a vector of speeds, including percentile: | 1354 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''' | 1355 aggregationFunc = lambda x: percentile(x, percentileFactor) # where percentileFactor is 85 for 85th percentile''' |
| 1356 if ignoreNInstantsAtEnds > 0: | 1356 speeds = self.getSpeeds(nInstantsIgnoredAtEnds) |
| 1357 speeds = self.getSpeeds()[ignoreNInstantsAtEnds:-ignoreNInstantsAtEnds] | |
| 1358 else: | |
| 1359 speeds = self.getSpeeds() | |
| 1360 if aggregationFunc(speeds) >= threshold: | 1357 if aggregationFunc(speeds) >= threshold: |
| 1361 self.setUserType(userType2Num['car']) | 1358 self.setUserType(userType2Num['car']) |
| 1362 else: | 1359 else: |
| 1363 self.setUserType(userType2Num['pedestrian']) | 1360 self.setUserType(userType2Num['pedestrian']) |
| 1364 | 1361 |
| 1365 def classifyUserTypeSpeed(self, speedProbabilities, aggregationFunc = median): | 1362 def classifyUserTypeSpeed(self, speedProbabilities, aggregationFunc = median, nInstantsIgnoredAtEnds = 0): |
| 1366 '''Classifies road user per road user type | 1363 '''Classifies road user per road user type |
| 1367 speedProbabilities are functions return P(speed|class) | 1364 speedProbabilities are functions return P(speed|class) |
| 1368 in a dictionary indexed by user type names | 1365 in a dictionary indexed by user type names |
| 1369 Returns probabilities for each class | 1366 Returns probabilities for each class |
| 1370 | 1367 |
| 1373 if abs(x-mu) < sigma: | 1370 if abs(x-mu) < sigma: |
| 1374 return 1 | 1371 return 1 |
| 1375 else: | 1372 else: |
| 1376 return x''' | 1373 return x''' |
| 1377 if not hasattr(self, 'aggregatedSpeed'): | 1374 if not hasattr(self, 'aggregatedSpeed'): |
| 1378 self.aggregatedSpeed = aggregationFunc(self.getSpeeds()) | 1375 self.aggregatedSpeed = aggregationFunc(self.getSpeeds(nInstantsIgnoredAtEnds)) |
| 1379 userTypeProbabilities = {} | 1376 userTypeProbabilities = {} |
| 1380 for userTypename in speedProbabilities: | 1377 for userTypename in speedProbabilities: |
| 1381 userTypeProbabilities[userType2Num[userTypename]] = speedProbabilities[userTypename](self.aggregatedSpeed) | 1378 userTypeProbabilities[userType2Num[userTypename]] = speedProbabilities[userTypename](self.aggregatedSpeed) |
| 1382 self.setUserType(utils.argmaxDict(userTypeProbabilities)) | 1379 self.setUserType(utils.argmaxDict(userTypeProbabilities)) |
| 1383 return userTypeProbabilities | 1380 return userTypeProbabilities |
| 1384 | 1381 |
| 1385 def initClassifyUserTypeHoGSVM(self, aggregationFunc = median): | 1382 def initClassifyUserTypeHoGSVM(self, aggregationFunc, pedBikeCarSVM, bikeCarSVM = None, pedBikeSpeedTreshold = float('Inf'), bikeCarSpeedThreshold = float('Inf'), nInstantsIgnoredAtEnds = 0): |
| 1386 '''Initializes the data structures for classification | 1383 '''Initializes the data structures for classification |
| 1387 | 1384 |
| 1388 TODO? compute speed for longest feature? | 1385 TODO? compute speed for longest feature?''' |
| 1389 Skip beginning and end of feature for speed? Offer options instead of median''' | 1386 self.aggregatedSpeed = aggregationFunc(self.getSpeeds(nInstantsIgnoredAtEnds)) |
| 1390 self.aggregatedSpeed = aggregationFunc(self.getSpeeds()) | 1387 if self.aggregatedSpeed < pedBikeSpeedTreshold or bikeCarSVM is None: |
| 1388 self.appearanceClassifier = pedBikeCarSVM | |
| 1389 elif self.aggregatedSpeed < bikeCarSpeedThreshold: | |
| 1390 self.appearanceClassifier = bikeCarSVM | |
| 1391 else: | |
| 1392 class CarClassifier: | |
| 1393 def predict(self, hog): | |
| 1394 return userType2Num['car'] | |
| 1395 self.appearanceClassifier = CarClassifier() | |
| 1396 | |
| 1391 self.userTypes = {} | 1397 self.userTypes = {} |
| 1392 | 1398 |
| 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): | 1399 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 | 1400 '''Extract the image box around the object and |
| 1395 applies the SVM model on it''' | 1401 applies the SVM model on it''' |
| 1396 croppedImg, yCropMin, yCropMax, xCropMin, xCropMax = imageBox(img, self, instant, homography, width, height, px, py, pixelThreshold) | 1402 croppedImg, yCropMin, yCropMax, xCropMin, xCropMax = cvutils.imageBox(img, self, instant, homography, width, height, px, py, minNPixels) |
| 1397 if len(croppedImg) > 0: # != [] | 1403 if len(croppedImg) > 0: |
| 1398 hog = array([cvutils.HOG(croppedImg)], dtype = np.float32) | 1404 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: | 1405 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: | 1406 else: |
| 1406 self.userTypes[instant] = userType2Num['unknown'] | 1407 self.userTypes[instant] = userType2Num['unknown'] |
| 1407 | 1408 |
| 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): | 1409 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 | 1410 '''Agregates SVM detections in each image and returns probability |
| 1410 (proportion of instants with classification in each category) | 1411 (proportion of instants with classification in each category) |
| 1411 | 1412 |
| 1412 iamges is a dictionary of images indexed by instant | 1413 images is a dictionary of images indexed by instant |
| 1413 With default parameters, the general (ped-bike-car) classifier will be used | 1414 With default parameters, the general (ped-bike-car) classifier will be used |
| 1414 TODO? consider all categories?''' | 1415 |
| 1415 if not hasattr(self, aggregatedSpeed) or not hasattr(self, userTypes): | 1416 Considered categories are the keys of speedProbabilities''' |
| 1417 if not hasattr(self, 'aggregatedSpeed') or not hasattr(self, 'userTypes'): | |
| 1416 print('Initilize the data structures for classification by HoG-SVM') | 1418 print('Initilize the data structures for classification by HoG-SVM') |
| 1417 self.initClassifyUserTypeHoGSVM(aggregationFunc) | 1419 self.initClassifyUserTypeHoGSVM(aggregationFunc, pedBikeCarSVM, bikeCarSVM, pedBikeSpeedTreshold, bikeCarSpeedThreshold, nInstantsIgnoredAtEnds) |
| 1418 | 1420 |
| 1419 if len(self.userTypes) != self.length(): # if classification has not been done previously | 1421 if len(self.userTypes) != self.length() and images is not None: # if classification has not been done previously |
| 1420 for t in self.getTimeInterval(): | 1422 for t in self.getTimeInterval(): |
| 1421 if t not in self.userTypes: | 1423 if t not in self.userTypes: |
| 1422 self.classifyUserTypeHoGSVMAtInstant(images[t], pedBikeCarSVM, t, homography, width, height, bikeCarSVM, pedBikeSpeedTreshold, bikeCarSpeedThreshold, px, py, pixelThreshold) | 1424 self.classifyUserTypeHoGSVMAtInstant(images[t], t, homography, width, height, px, py, minNPixels) |
| 1423 # compute P(Speed|Class) | 1425 # compute P(Speed|Class) |
| 1424 if speedProbabilities is None: # equiprobable information from speed | 1426 if speedProbabilities is None or self.aggregatedSpeed < minSpeedEquiprobable: # equiprobable information from speed |
| 1425 userTypeProbabilities = {userType2Num['car']: 1., userType2Num['pedestrian']: 1., userType2Num['bicycle']: 1.} | 1427 userTypeProbabilities = {userType2Num['car']: 1., userType2Num['pedestrian']: 1., userType2Num['bicycle']: 1.} |
| 1426 else: | 1428 else: |
| 1427 userTypeProbabilities = {userType2Num[userTypename]: speedProbabilities[userTypename](self.aggregatedSpeed) for userTypename in speedProbabilities} | 1429 userTypeProbabilities = {userType2Num[userTypename]: speedProbabilities[userTypename](self.aggregatedSpeed) for userTypename in speedProbabilities} |
| 1428 # result is P(Class|Appearance) x P(Speed|Class) | 1430 # 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 | 1431 nInstantsUserType = {userTypeNum: 0 for userTypeNum in userTypeProbabilities}# number of instants the object is classified as userTypename |
| 1430 for t in self.userTypes: | 1432 for t in self.userTypes: |
| 1431 nInstantsUserType[self.userTypes[t]] += 1 | 1433 nInstantsUserType[self.userTypes[t]] = nInstantsUserType.get(self.userTypes[t], 0) + 1 |
| 1432 for userTypename in userTypeProbabilities: | 1434 for userTypeNum in userTypeProbabilities: |
| 1433 userTypeProbabilities[userTypename] *= nInstantsUserType[userTypename] | 1435 userTypeProbabilities[userTypeNum] *= nInstantsUserType[userTypeNum] |
| 1434 # class is the user type that maximizes usertype probabilities | 1436 # class is the user type that maximizes usertype probabilities |
| 1435 self.setUserType(utils.argmaxDict(userTypeProbabilities)) | 1437 self.setUserType(utils.argmaxDict(userTypeProbabilities)) |
| 1436 | 1438 |
| 1437 def classifyUserTypeArea(self, areas, homography): | 1439 def classifyUserTypeArea(self, areas, homography): |
| 1438 '''Classifies the object based on its location (projected to image space) | 1440 '''Classifies the object based on its location (projected to image space) |
