Mercurial Hosting > traffic-intelligence
comparison trafficintelligence/moving.py @ 1110:6bbcd9433732
formatting and addition of one method to CurvilinearTrajectory
author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
---|---|
date | Mon, 06 May 2019 16:16:28 -0400 |
parents | 6e8ab471ebd4 |
children | 345cd9cd62d8 |
comparison
equal
deleted
inserted
replaced
1109:6e8ab471ebd4 | 1110:6bbcd9433732 |
---|---|
271 def plotSegment(p1, p2, options = 'o', **kwargs): | 271 def plotSegment(p1, p2, options = 'o', **kwargs): |
272 plot([p1.x, p2.x], [p1.y, p2.y], options, **kwargs) | 272 plot([p1.x, p2.x], [p1.y, p2.y], options, **kwargs) |
273 | 273 |
274 def angle(self): | 274 def angle(self): |
275 return atan2(self.y, self.x) | 275 return atan2(self.y, self.x) |
276 | 276 |
277 def norm2Squared(self): | 277 def norm2Squared(self): |
278 '''2-norm distance (Euclidean distance)''' | 278 '''2-norm distance (Euclidean distance)''' |
279 return self.x**2+self.y**2 | 279 return self.x**2+self.y**2 |
280 | 280 |
281 def norm2(self): | 281 def norm2(self): |
282 '''2-norm distance (Euclidean distance)''' | 282 '''2-norm distance (Euclidean distance)''' |
283 return sqrt(self.norm2Squared()) | 283 return sqrt(self.norm2Squared()) |
284 | 284 |
285 def norm1(self): | 285 def norm1(self): |
286 return abs(self.x)+abs(self.y) | 286 return abs(self.x)+abs(self.y) |
287 | 287 |
288 def normMax(self): | 288 def normMax(self): |
289 return max(abs(self.x),abs(self.y)) | 289 return max(abs(self.x),abs(self.y)) |
290 | 290 |
291 def aslist(self): | 291 def aslist(self): |
292 return [self.x, self.y] | 292 return [self.x, self.y] |
344 return p1.x*p2.y-p1.y*p2.x | 344 return p1.x*p2.y-p1.y*p2.x |
345 | 345 |
346 @staticmethod | 346 @staticmethod |
347 def parallel(p1, p2): | 347 def parallel(p1, p2): |
348 return Point.cross(p1, p2) == 0. | 348 return Point.cross(p1, p2) == 0. |
349 | 349 |
350 @staticmethod | 350 @staticmethod |
351 def cosine(p1, p2): | 351 def cosine(p1, p2): |
352 return Point.dot(p1,p2)/(p1.norm2()*p2.norm2()) | 352 return Point.dot(p1,p2)/(p1.norm2()*p2.norm2()) |
353 | 353 |
354 @staticmethod | 354 @staticmethod |
463 Y = (-(qx)*(p0y-p1y)-(qy*(p0y-p1y)**2)/(p0x-p1x)+p0x**2*(p0y-p1y)/(p0x-p1x)-p0x*p1x*(p0y-p1y)/(p0x-p1x)-p0y*(p0x-p1x))/(p1x-p0x-(p0y-p1y)**2/(p0x-p1x)) | 463 Y = (-(qx)*(p0y-p1y)-(qy*(p0y-p1y)**2)/(p0x-p1x)+p0x**2*(p0y-p1y)/(p0x-p1x)-p0x*p1x*(p0y-p1y)/(p0x-p1x)-p0y*(p0x-p1x))/(p1x-p0x-(p0y-p1y)**2/(p0x-p1x)) |
464 X = (-Y*(p1y-p0y)+qx*(p1x-p0x)+qy*(p1y-p0y))/(p1x-p0x) | 464 X = (-Y*(p1y-p0y)+qx*(p1x-p0x)+qy*(p1y-p0y))/(p1x-p0x) |
465 except ZeroDivisionError: | 465 except ZeroDivisionError: |
466 print('Error: Division by zero in ppldb2p. Please report this error with the full traceback:') | 466 print('Error: Division by zero in ppldb2p. Please report this error with the full traceback:') |
467 print('qx={0}, qy={1}, p0x={2}, p0y={3}, p1x={4}, p1y={5}...'.format(qx, qy, p0x, p0y, p1x, p1y)) | 467 print('qx={0}, qy={1}, p0x={2}, p0y={3}, p1x={4}, p1y={5}...'.format(qx, qy, p0x, p0y, p1x, p1y)) |
468 import pdb; pdb.set_trace() | 468 import pdb; |
469 return Point(X,Y) | 469 pdb.set_trace() |
470 return Point(X, Y) | |
470 | 471 |
471 def getSYfromXY(p, alignments, goodEnoughAlignmentDistance = 0.5): | 472 def getSYfromXY(p, alignments, goodEnoughAlignmentDistance = 0.5): |
472 ''' Snap a point p to its nearest subsegment of it's nearest alignment (from the list alignments). | 473 ''' Snap a point p to its nearest subsegment of it's nearest alignment (from the list alignments). |
473 A alignment is a list of points (class Point), most likely a trajectory. | 474 A alignment is a list of points (class Point), most likely a trajectory. |
474 | 475 |
539 return alignment[i-1] + normalizedV*d + orthoNormalizedV*y | 540 return alignment[i-1] + normalizedV*d + orthoNormalizedV*y |
540 else: | 541 else: |
541 print('Curvilinear point {} is past the end of the alignement'.format((s, y, alignmentNum))) | 542 print('Curvilinear point {} is past the end of the alignement'.format((s, y, alignmentNum))) |
542 return None | 543 return None |
543 | 544 |
544 | 545 |
545 class NormAngle(object): | 546 class NormAngle(object): |
546 '''Alternate encoding of a point, by its norm and orientation''' | 547 '''Alternate encoding of a point, by its norm and orientation''' |
547 | 548 |
548 def __init__(self, norm, angle): | 549 def __init__(self, norm, angle): |
549 self.norm = norm | 550 self.norm = norm |
550 self.angle = angle | 551 self.angle = angle |
551 | 552 |
552 @staticmethod | 553 @staticmethod |
553 def fromPoint(p): | 554 def fromPoint(p): |
554 norm = p.norm2() | 555 norm = p.norm2() |
555 if norm > 0: | 556 if norm > 0: |
556 angle = p.angle() | 557 angle = p.angle() |
596 return FlowVector(self.position.__mul__(alpha), self.velocity.__mul__(alpha)) | 597 return FlowVector(self.position.__mul__(alpha), self.velocity.__mul__(alpha)) |
597 | 598 |
598 def plot(self, options = '', **kwargs): | 599 def plot(self, options = '', **kwargs): |
599 plot([self.position.x, self.position.x+self.velocity.x], [self.position.y, self.position.y+self.velocity.y], options, **kwargs) | 600 plot([self.position.x, self.position.x+self.velocity.x], [self.position.y, self.position.y+self.velocity.y], options, **kwargs) |
600 self.position.plot(options+'x', **kwargs) | 601 self.position.plot(options+'x', **kwargs) |
601 | 602 |
602 @staticmethod | 603 @staticmethod |
603 def similar(f1, f2, maxDistance2, maxDeltavelocity2): | 604 def similar(f1, f2, maxDistance2, maxDeltavelocity2): |
604 return (f1.position-f2.position).norm2Squared()<maxDistance2 and (f1.velocity-f2.velocity).norm2Squared()<maxDeltavelocity2 | 605 return (f1.position-f2.position).norm2Squared()<maxDistance2 and (f1.velocity-f2.velocity).norm2Squared()<maxDeltavelocity2 |
605 | 606 |
606 def intersection(p1, p2, p3, p4): | 607 def intersection(p1, p2, p3, p4): |
623 # from numpy.linalg import linalg | 624 # from numpy.linalg import linalg |
624 # A = matrix([[dp1.y, -dp1.x], | 625 # A = matrix([[dp1.y, -dp1.x], |
625 # [dp2.y, -dp2.x]]) | 626 # [dp2.y, -dp2.x]]) |
626 # B = matrix([[dp1.y*p1.x-dp1.x*p1.y], | 627 # B = matrix([[dp1.y*p1.x-dp1.x*p1.y], |
627 # [dp2.y*p2.x-dp2.x*p2.y]]) | 628 # [dp2.y*p2.x-dp2.x*p2.y]]) |
628 | 629 |
629 # if linalg.det(A) == 0: | 630 # if linalg.det(A) == 0: |
630 # return None | 631 # return None |
631 # else: | 632 # else: |
632 # intersection = linalg.solve(A,B) | 633 # intersection = linalg.solve(A,B) |
633 # return Point(intersection[0,0], intersection[1,0]) | 634 # return Point(intersection[0,0], intersection[1,0]) |
653 inter = intersection(p1, p2, p3, p4) | 654 inter = intersection(p1, p2, p3, p4) |
654 if inter is not None and utils.inBetween(p3.x, p4.x, inter.x) and utils.inBetween(p3.y, p4.y, inter.y): | 655 if inter is not None and utils.inBetween(p3.x, p4.x, inter.x) and utils.inBetween(p3.y, p4.y, inter.y): |
655 return inter | 656 return inter |
656 else: | 657 else: |
657 return None | 658 return None |
658 | 659 |
659 | 660 |
660 class Trajectory(object): | 661 class Trajectory(object): |
661 '''Class for trajectories: temporal sequence of positions | 662 '''Class for trajectories: temporal sequence of positions |
662 | 663 |
663 The class is iterable''' | 664 The class is iterable''' |
790 def getYCoordinates(self): | 791 def getYCoordinates(self): |
791 return self.positions[1] | 792 return self.positions[1] |
792 | 793 |
793 def asArray(self): | 794 def asArray(self): |
794 return array(self.positions) | 795 return array(self.positions) |
795 | 796 |
796 def xBounds(self): | 797 def xBounds(self): |
797 # look for function that does min and max in one pass | 798 # look for function that does min and max in one pass |
798 return Interval(min(self.getXCoordinates()), max(self.getXCoordinates())) | 799 return Interval(min(self.getXCoordinates()), max(self.getXCoordinates())) |
799 | 800 |
800 def yBounds(self): | 801 def yBounds(self): |
801 # look for function that does min and max in one pass | 802 # look for function that does min and max in one pass |
802 return Interval(min(self.getYCoordinates()), max(self.getYCoordinates())) | 803 return Interval(min(self.getYCoordinates()), max(self.getYCoordinates())) |
803 | 804 |
804 def add(self, traj2): | 805 def add(self, traj2): |
805 '''Returns a new trajectory of the same length''' | 806 '''Returns a new trajectory of the same length''' |
806 if self.length() != traj2.length(): | 807 if self.length() != traj2.length(): |
807 print('Trajectories of different lengths') | 808 print('Trajectories of different lengths') |
808 return None | 809 return None |
949 '''Returns a list of the indices at which the trajectory | 950 '''Returns a list of the indices at which the trajectory |
950 intersects with the line going through p1 and p2 | 951 intersects with the line going through p1 and p2 |
951 Returns an empty list if there is no crossing''' | 952 Returns an empty list if there is no crossing''' |
952 indices = [] | 953 indices = [] |
953 intersections = [] | 954 intersections = [] |
954 | 955 |
955 for i in range(self.length()-1): | 956 for i in range(self.length()-1): |
956 q1=self.__getitem__(i) | 957 q1=self.__getitem__(i) |
957 q2=self.__getitem__(i+1) | 958 q2=self.__getitem__(i+1) |
958 p = segmentLineIntersection(p1, p2, q1, q2) | 959 p = segmentLineIntersection(p1, p2, q1, q2) |
959 if p is not None: | 960 if p is not None: |
1056 self.positions = [S,Y] | 1057 self.positions = [S,Y] |
1057 if lanes is None or len(lanes) != self.length(): | 1058 if lanes is None or len(lanes) != self.length(): |
1058 self.lanes = [None]*int(self.length()) | 1059 self.lanes = [None]*int(self.length()) |
1059 else: | 1060 else: |
1060 self.lanes = lanes | 1061 self.lanes = lanes |
1061 | 1062 |
1062 @staticmethod | 1063 @staticmethod |
1063 def generate(s, v, nPoints, lane, y = 0): | 1064 def generate(s, v, nPoints, lane, y = 0): |
1064 '''s is initial position, v is velocity | 1065 '''s is initial position, v is velocity |
1065 0 in lateral coordinate by default | 1066 0 in lateral coordinate by default |
1066 TODO 2D velocity for lane change?''' | 1067 TODO 2D velocity for lane change?''' |
1132 raise TypeError("Invalid argument type.") | 1133 raise TypeError("Invalid argument type.") |
1133 #elif isinstance( key, slice ): | 1134 #elif isinstance( key, slice ): |
1134 | 1135 |
1135 def getSCoordinates(self): | 1136 def getSCoordinates(self): |
1136 return self.getXCoordinates() | 1137 return self.getXCoordinates() |
1137 | 1138 |
1138 def getLanes(self): | 1139 def getLanes(self): |
1139 return self.lanes | 1140 return self.lanes |
1140 | 1141 |
1141 def getSCoordAt(self, i): | 1142 def getSCoordAt(self, i): |
1142 return self.positions[0][i] | 1143 return self.positions[0][i] |
1161 self.lanes.append(lane) | 1162 self.lanes.append(lane) |
1162 | 1163 |
1163 def addPosition(self, p): | 1164 def addPosition(self, p): |
1164 'Adds position in the point format for curvilinear of list with 3 values' | 1165 'Adds position in the point format for curvilinear of list with 3 values' |
1165 self.addPositionSYL(p[0], p[1], p[2]) | 1166 self.addPositionSYL(p[0], p[1], p[2]) |
1167 | |
1168 def duplicateLastPosition(self): | |
1169 super(CurvilinearTrajectory, self).duplicateLastPosition() | |
1170 self.lanes.append(self.lanes[-1]) | |
1166 | 1171 |
1167 def setPosition(self, i, s, y, lane): | 1172 def setPosition(self, i, s, y, lane): |
1168 self.setPositionXY(i, s, y) | 1173 self.setPositionXY(i, s, y) |
1169 if i < self.__len__(): | 1174 if i < self.__len__(): |
1170 self.lanes[i] = lane | 1175 self.lanes[i] = lane |
1213 | 1218 |
1214 class CarClassifier: | 1219 class CarClassifier: |
1215 def predict(self, hog): | 1220 def predict(self, hog): |
1216 return userType2Num['car'] | 1221 return userType2Num['car'] |
1217 carClassifier = CarClassifier() | 1222 carClassifier = CarClassifier() |
1218 | 1223 |
1219 class MovingObject(STObject, VideoFilenameAddable): | 1224 class MovingObject(STObject, VideoFilenameAddable): |
1220 '''Class for moving objects: a spatio-temporal object | 1225 '''Class for moving objects: a spatio-temporal object |
1221 with a trajectory and a geometry (constant volume over time) | 1226 with a trajectory and a geometry (constant volume over time) |
1222 and a usertype (e.g. road user) coded as a number (see userTypeNames) | 1227 and a usertype (e.g. road user) coded as a number (see userTypeNames) |
1223 ''' | 1228 ''' |
1233 self.geometry = geometry | 1238 self.geometry = geometry |
1234 self.userType = userType | 1239 self.userType = userType |
1235 self.setNObjects(nObjects) # a feature has None for nObjects | 1240 self.setNObjects(nObjects) # a feature has None for nObjects |
1236 self.features = None | 1241 self.features = None |
1237 # compute bounding polygon from trajectory | 1242 # compute bounding polygon from trajectory |
1238 | 1243 |
1239 @staticmethod | 1244 @staticmethod |
1240 def croppedTimeInterval(obj, value, after = True): | 1245 def croppedTimeInterval(obj, value, after = True): |
1241 newTimeInterval = TimeInterval(obj.getFirstInstant(), min(value, obj.getLastInstant())) if after else TimeInterval(max(obj.getFirstInstant(), value), obj.getLastInstant()) | 1246 newTimeInterval = TimeInterval(obj.getFirstInstant(), min(value, obj.getLastInstant())) if after else TimeInterval(max(obj.getFirstInstant(), value), obj.getLastInstant()) |
1242 if obj.positions is not None : | 1247 if obj.positions is not None : |
1243 newPositions = obj.positions[slice(newTimeInterval.first, newTimeInterval.last+1)] | 1248 newPositions = obj.positions[slice(newTimeInterval.first, newTimeInterval.last+1)] |
1517 return [(1-alpha)*p1[0]+alpha*p2[0], (1-alpha)*p1[1]+alpha*p2[1], lane] | 1522 return [(1-alpha)*p1[0]+alpha*p2[0], (1-alpha)*p1[1]+alpha*p2[1], lane] |
1518 else: | 1523 else: |
1519 print('Object {} does not exist at {}'.format(self.getNum(), t)) | 1524 print('Object {} does not exist at {}'.format(self.getNum(), t)) |
1520 else: | 1525 else: |
1521 print('Object {} has no curvilinear positions'.format(self.getNum())) | 1526 print('Object {} has no curvilinear positions'.format(self.getNum())) |
1522 | 1527 |
1523 def setUserType(self, userType): | 1528 def setUserType(self, userType): |
1524 self.userType = userType | 1529 self.userType = userType |
1525 | 1530 |
1526 def getNObjects(self): | 1531 def getNObjects(self): |
1527 return self.nObjects | 1532 return self.nObjects |
1530 if nObjects is None or nObjects >= 1: | 1535 if nObjects is None or nObjects >= 1: |
1531 self.nObjects = nObjects | 1536 self.nObjects = nObjects |
1532 else: | 1537 else: |
1533 print('Number of objects represented by object {} must be greater or equal to 1 ({})'.format(self.getNum(), nObjects)) | 1538 print('Number of objects represented by object {} must be greater or equal to 1 ({})'.format(self.getNum(), nObjects)) |
1534 self.nObjects = None | 1539 self.nObjects = None |
1535 | 1540 |
1536 def setFeatures(self, features, featuresOrdered = False): | 1541 def setFeatures(self, features, featuresOrdered = False): |
1537 '''Sets the features in the features field based on featureNumbers | 1542 '''Sets the features in the features field based on featureNumbers |
1538 if not all features are loaded from 0, one needs to renumber in a dict''' | 1543 if not all features are loaded from 0, one needs to renumber in a dict''' |
1539 if featuresOrdered: | 1544 if featuresOrdered: |
1540 tmp = features | 1545 tmp = features |
1589 '''Returns the 1-D acceleration from the 1-D speeds | 1594 '''Returns the 1-D acceleration from the 1-D speeds |
1590 Caution about previously filtered data''' | 1595 Caution about previously filtered data''' |
1591 if speeds is None: | 1596 if speeds is None: |
1592 speeds = self.getSpeeds(nInstantsIgnoredAtEnds) | 1597 speeds = self.getSpeeds(nInstantsIgnoredAtEnds) |
1593 return savgol_filter(speeds, window_length, polyorder, 1, delta, axis, mode, cval) | 1598 return savgol_filter(speeds, window_length, polyorder, 1, delta, axis, mode, cval) |
1594 | 1599 |
1595 def getSpeedIndicator(self): | 1600 def getSpeedIndicator(self): |
1596 from indicators import SeverityIndicator | 1601 from indicators import SeverityIndicator |
1597 return SeverityIndicator('Speed', {t:self.getVelocityAtInstant(t).norm2() for t in self.getTimeInterval()}) | 1602 return SeverityIndicator('Speed', {t:self.getVelocityAtInstant(t).norm2() for t in self.getTimeInterval()}) |
1598 | 1603 |
1599 def getPositionAt(self, i): | 1604 def getPositionAt(self, i): |
1620 def getCurvilinearVelocityAtInstant(self, i): | 1625 def getCurvilinearVelocityAtInstant(self, i): |
1621 return self.curvilinearVelocities[i-self.getFirstInstant()] | 1626 return self.curvilinearVelocities[i-self.getFirstInstant()] |
1622 | 1627 |
1623 def getXCoordinates(self): | 1628 def getXCoordinates(self): |
1624 return self.positions.getXCoordinates() | 1629 return self.positions.getXCoordinates() |
1625 | 1630 |
1626 def getYCoordinates(self): | 1631 def getYCoordinates(self): |
1627 return self.positions.getYCoordinates() | 1632 return self.positions.getYCoordinates() |
1628 | 1633 |
1629 def plot(self, options = '', withOrigin = False, timeStep = 1, withFeatures = False, withIds = False, **kwargs): | 1634 def plot(self, options = '', withOrigin = False, timeStep = 1, withFeatures = False, withIds = False, **kwargs): |
1630 if withIds: | 1635 if withIds: |
1631 objNum = self.getNum() | 1636 objNum = self.getNum() |
1632 else: | 1637 else: |
1633 objNum = None | 1638 objNum = None |
1688 else: | 1693 else: |
1689 instant2 = _instant2 | 1694 instant2 = _instant2 |
1690 positions1 = [f.getPositionAtInstant(instant1).astuple() for f in obj1.features if f.existsAtInstant(instant1)] | 1695 positions1 = [f.getPositionAtInstant(instant1).astuple() for f in obj1.features if f.existsAtInstant(instant1)] |
1691 positions2 = [f.getPositionAtInstant(instant2).astuple() for f in obj2.features if f.existsAtInstant(instant2)] | 1696 positions2 = [f.getPositionAtInstant(instant2).astuple() for f in obj2.features if f.existsAtInstant(instant2)] |
1692 return cdist(positions1, positions2, metric = 'euclidean') | 1697 return cdist(positions1, positions2, metric = 'euclidean') |
1693 | 1698 |
1694 @staticmethod | 1699 @staticmethod |
1695 def minDistance(obj1, obj2, instant1, instant2 = None): | 1700 def minDistance(obj1, obj2, instant1, instant2 = None): |
1696 return MovingObject.distances(obj1, obj2, instant1, instant2).min() | 1701 return MovingObject.distances(obj1, obj2, instant1, instant2).min() |
1697 | 1702 |
1698 @staticmethod | 1703 @staticmethod |
1712 tMaxFeatures = t | 1717 tMaxFeatures = t |
1713 return MovingObject.maxDistance(self, self, tMaxFeatures) | 1718 return MovingObject.maxDistance(self, self, tMaxFeatures) |
1714 else: | 1719 else: |
1715 print('Load features to compute a maximum size') | 1720 print('Load features to compute a maximum size') |
1716 return None | 1721 return None |
1717 | 1722 |
1718 def setRoutes(self, startRouteID, endRouteID): | 1723 def setRoutes(self, startRouteID, endRouteID): |
1719 self.startRouteID = startRouteID | 1724 self.startRouteID = startRouteID |
1720 self.endRouteID = endRouteID | 1725 self.endRouteID = endRouteID |
1721 | 1726 |
1722 def getInstantsCrossingLane(self, p1, p2): | 1727 def getInstantsCrossingLane(self, p1, p2): |
1723 '''Returns the instant(s) | 1728 '''Returns the instant(s) |
1724 at which the object passes from one side of the segment to the other | 1729 at which the object passes from one side of the segment to the other |
1725 empty list if there is no crossing''' | 1730 empty list if there is no crossing''' |
1726 indices, intersections = self.positions.getIntersections(p1, p2) | 1731 indices, intersections = self.positions.getIntersections(p1, p2) |
1732 self.prototypeSimilarities = [] | 1737 self.prototypeSimilarities = [] |
1733 for proto in prototypes: | 1738 for proto in prototypes: |
1734 lcss.similarities(proto.getMovingObject().getPositions().asArray().T, self.getPositions().asArray().T) | 1739 lcss.similarities(proto.getMovingObject().getPositions().asArray().T, self.getPositions().asArray().T) |
1735 similarities = lcss.similarityTable[-1, :-1].astype(float) | 1740 similarities = lcss.similarityTable[-1, :-1].astype(float) |
1736 self.prototypeSimilarities.append(similarities/minimum(arange(1., len(similarities)+1), proto.getMovingObject().length()*ones(len(similarities)))) | 1741 self.prototypeSimilarities.append(similarities/minimum(arange(1., len(similarities)+1), proto.getMovingObject().length()*ones(len(similarities)))) |
1737 | 1742 |
1738 @staticmethod | 1743 @staticmethod |
1739 def computePET(obj1, obj2, collisionDistanceThreshold): | 1744 def computePET(obj1, obj2, collisionDistanceThreshold): |
1740 '''Post-encroachment time based on distance threshold | 1745 '''Post-encroachment time based on distance threshold |
1741 | 1746 |
1742 Returns the smallest time difference when the object positions are within collisionDistanceThreshold | 1747 Returns the smallest time difference when the object positions are within collisionDistanceThreshold |
1809 ### | 1814 ### |
1810 def classifyUserTypeSpeedMotorized(self, threshold, aggregationFunc = median, nInstantsIgnoredAtEnds = 0): | 1815 def classifyUserTypeSpeedMotorized(self, threshold, aggregationFunc = median, nInstantsIgnoredAtEnds = 0): |
1811 '''Classifies slow and fast road users | 1816 '''Classifies slow and fast road users |
1812 slow: non-motorized -> pedestrians | 1817 slow: non-motorized -> pedestrians |
1813 fast: motorized -> cars | 1818 fast: motorized -> cars |
1814 | 1819 |
1815 aggregationFunc can be any function that can be applied to a vector of speeds, including percentile: | 1820 aggregationFunc can be any function that can be applied to a vector of speeds, including percentile: |
1816 aggregationFunc = lambda x: percentile(x, percentileFactor) # where percentileFactor is 85 for 85th percentile''' | 1821 aggregationFunc = lambda x: percentile(x, percentileFactor) # where percentileFactor is 85 for 85th percentile''' |
1817 speeds = self.getSpeeds(nInstantsIgnoredAtEnds) | 1822 speeds = self.getSpeeds(nInstantsIgnoredAtEnds) |
1818 if aggregationFunc(speeds) >= threshold: | 1823 if aggregationFunc(speeds) >= threshold: |
1819 self.setUserType(userType2Num['car']) | 1824 self.setUserType(userType2Num['car']) |
1968 return '{} {} {}'.format(self.filename, self.num, self.trajectoryType) | 1973 return '{} {} {}'.format(self.filename, self.num, self.trajectoryType) |
1969 def __eq__(self, p2): | 1974 def __eq__(self, p2): |
1970 return self.filename == p2.filename and self.num == p2.num and self.trajectoryType == p2.trajectoryType | 1975 return self.filename == p2.filename and self.num == p2.num and self.trajectoryType == p2.trajectoryType |
1971 def __hash__(self): | 1976 def __hash__(self): |
1972 return hash((self.filename, self.num, self.trajectoryType)) | 1977 return hash((self.filename, self.num, self.trajectoryType)) |
1973 | 1978 |
1974 ################## | 1979 ################## |
1975 # Annotations | 1980 # Annotations |
1976 ################## | 1981 ################## |
1977 | 1982 |
1978 class BBMovingObject(MovingObject): | 1983 class BBMovingObject(MovingObject): |
2098 print('{} '.format(t)+', '.join(['{} {}'.format(k.getNum(), v.getNum()) for k,v in matches.items()])) | 2103 print('{} '.format(t)+', '.join(['{} {}'.format(k.getNum(), v.getNum()) for k,v in matches.items()])) |
2099 if returnMatches: | 2104 if returnMatches: |
2100 for a,o in matches.items(): | 2105 for a,o in matches.items(): |
2101 gtMatches[a.getNum()][t] = o.getNum() | 2106 gtMatches[a.getNum()][t] = o.getNum() |
2102 toMatches[o.getNum()][t] = a.getNum() | 2107 toMatches[o.getNum()][t] = a.getNum() |
2103 | 2108 |
2104 # compute metrics elements | 2109 # compute metrics elements |
2105 ct += len(matches) | 2110 ct += len(matches) |
2106 mt += nGTs-len(matches) | 2111 mt += nGTs-len(matches) |
2107 fpt += nTOs-len(matches) | 2112 fpt += nTOs-len(matches) |
2108 gt += nGTs | 2113 gt += nGTs |
2121 if debug: | 2126 if debug: |
2122 for mm in set(mismatches): | 2127 for mm in set(mismatches): |
2123 print('{} {}'.format(type(mm), mm.getNum())) | 2128 print('{} {}'.format(type(mm), mm.getNum())) |
2124 # some object mismatches may appear twice | 2129 # some object mismatches may appear twice |
2125 mme += len(set(mismatches)) | 2130 mme += len(set(mismatches)) |
2126 | 2131 |
2127 if ct > 0: | 2132 if ct > 0: |
2128 motp = dist/ct | 2133 motp = dist/ct |
2129 else: | 2134 else: |
2130 motp = None | 2135 motp = None |
2131 if gt > 0: | 2136 if gt > 0: |