changeset 1177:aa88acf06876

rewrote object concatenation method, cleaner
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Thu, 24 Mar 2022 16:07:51 -0400
parents 5874ece33637
children ee3eaf902b83 7117a31555c1
files trafficintelligence/moving.py trafficintelligence/storage.py trafficintelligence/tests/moving.txt
diffstat 3 files changed, 101 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/trafficintelligence/moving.py	Thu Feb 17 10:55:11 2022 -0500
+++ b/trafficintelligence/moving.py	Thu Mar 24 16:07:51 2022 -0400
@@ -750,8 +750,8 @@
 
     def append(self,other):
         '''adds positions of other to the trajectory (in-place modification)'''
-        for p in other:
-            self.addPosition(p)
+        for i in range(2):
+            self.positions[i] += other.positions[i]
 
     def setPositionXY(self, i, x, y):
         if i < self.__len__():
@@ -767,7 +767,7 @@
 
     def addPosition(self, p):
         self.addPositionXY(p.x, p.y)
-
+        
     def duplicateLastPosition(self):
         self.positions[0].append(self.positions[0][-1])
         self.positions[1].append(self.positions[1][-1])
@@ -1174,6 +1174,10 @@
         else:
             return None
 
+    def append(self, other):
+        Trajectory.append(self, other)
+        self.lanes.append(other.getLanes())
+        
     def addPositionSYL(self, s, y, lane = None):
         self.addPositionXY(s,y)
         self.lanes.append(lane)
@@ -1312,59 +1316,61 @@
         inter, self.positions, self.velocities = MovingObject.aggregateTrajectories(self.features, self.getTimeInterval())
 
     @staticmethod
-    def concatenate(obj1, obj2, num = None, newFeatureNum = None, minFeatureLength = 5):
+    def concatenate(obj1, obj2, num = None, newFeatureNum = None):
         '''Concatenates two objects, whether overlapping temporally or not
 
-        Positions will be recomputed features are merged
-        Otherwise, only featureNumbers and/or features will be merged
-        minFeatureLength enforces a minimum length to avoid small features
-        (and smaller velocities that are not saved)'''
+        Positions will be recomputed if features are merged
+        Otherwise, only featureNumbers and/or features will be merged'''
         if num is None:
             newNum = obj1.getNum()
         else:
             newNum = num
         commonTimeInterval = obj1.commonTimeInterval(obj2)
-        if commonTimeInterval.empty():
-            #print('The two objects\' time intervals do not overlap: obj1 {} and obj2 {}'.format(obj1.getTimeInterval(), obj2.getTimeInterval()))
-            emptyInterval = TimeInterval(min(obj1.getLastInstant(),obj2.getLastInstant()), max(obj1.getFirstInstant(),obj2.getFirstInstant()))
-            if obj1.existsAtInstant(emptyInterval.last):
-                firstObject = obj2
-                secondObject = obj1
+        emptyInterval = TimeInterval(min(obj1.getLastInstant(),obj2.getLastInstant()), max(obj1.getFirstInstant(),obj2.getFirstInstant()))
+        if commonTimeInterval.empty() and emptyInterval.length() >= 3:
+            if newFeatureNum is None:
+                print('Not merging objects {} and {}, missing new feature number'.format(obj1.getNum(),obj2.getNum()))
+                return None, None
             else:
-                firstObject = obj1
-                secondObject = obj2
-            v = (secondObject.getPositionAtInstant(emptyInterval.last)-firstObject.getPositionAtInstant(emptyInterval.first)).divide(emptyInterval.length()-1)
-            positions = copy.deepcopy(firstObject.getPositions())
-            velocities = copy.deepcopy(firstObject.getPositions())
-            featurePositions = Trajectory()
-            featureVelocities = Trajectory()
-            p = firstObject.getPositionAtInstant(emptyInterval.first)+v
-            for t in range(emptyInterval.first+1, emptyInterval.last+1):
-            	positions.addPosition(p)
-            	velocities.addPosition(v)
-            	featurePositions.addPosition(p)
-            	featureVelocities.addPosition(v)
-            	p=p+v
-            for t in secondObject.getTimeInterval():
-                p = secondObject.getPositionAtInstant(t)
-                v = secondObject.getVelocityAtInstant(t)
-                positions.addPosition(p)
-                velocities.addPosition(v)
-                if featurePositions.length() < minFeatureLength:
+                if obj1.existsAtInstant(emptyInterval.last):
+                    firstObject = obj2
+                    secondObject = obj1
+                else:
+                    firstObject = obj1
+                    secondObject = obj2
+                v = (secondObject.getPositionAtInstant(emptyInterval.last)-firstObject.getPositionAtInstant(emptyInterval.first)).divide(emptyInterval.length()-1)
+                positions = copy.deepcopy(firstObject.getPositions())
+                velocities = copy.deepcopy(firstObject.getPositions())
+                featurePositions = Trajectory()
+                featureVelocities = Trajectory()
+                p = firstObject.getPositionAtInstant(emptyInterval.first)
+                # init new feature with position at last instant of 1st obj
+                featurePositions.addPosition(p)
+                featureVelocities.addPosition(v)
+                for t in range(emptyInterval.first+1, emptyInterval.last):
+                    p=p+v
+                    positions.addPosition(p)
+                    velocities.addPosition(v)
                     featurePositions.addPosition(p)
                     featureVelocities.addPosition(v)
-            newObject = MovingObject(newNum, TimeInterval(firstObject.getFirstInstant(), secondObject.getLastInstant()), positions, velocities, nObjects = 1)
-            if hasattr(obj1, 'featureNumbers') and hasattr(obj2, 'featureNumbers'):
-                if newFeatureNum is not None:
+                # last position to feature
+                p = secondObject.getPositionAtInstant(emptyInterval.last)
+                v = secondObject.getVelocityAtInstant(emptyInterval.last)
+                featurePositions.addPosition(p)
+                featureVelocities.addPosition(v)
+                # copy second trajectory
+                positions.append(secondObject.getPositions())
+                velocities.append(secondObject.getVelocities())
+                newObject = MovingObject(newNum, TimeInterval(firstObject.getFirstInstant(), secondObject.getLastInstant()), positions, velocities, nObjects = 1)
+                newFeature = MovingObject(newFeatureNum, emptyInterval, featurePositions, featureVelocities)
+                if hasattr(obj1, 'featureNumbers') and hasattr(obj2, 'featureNumbers'):
                     newObject.featureNumbers = obj1.featureNumbers+obj2.featureNumbers+[newFeatureNum]
-                else:
-                    print('Issue, new created feature has no num id')
-            if obj1.hasFeatures() and obj2.hasFeatures():
-                newObject.features = obj1.getFeatures()+obj2.getFeatures()+[MovingObject(newFeatureNum, TimeInterval(emptyInterval.first+1, emptyInterval.first+featurePositions.length()), featurePositions, featureVelocities)]
-                newObject.updatePositions()
+                if obj1.hasFeatures() and obj2.hasFeatures():
+                    newObject.features = obj1.getFeatures()+obj2.getFeatures()+[newFeature]
         else: # time intervals overlap
             newTimeInterval = TimeInterval.union(obj1.getTimeInterval(), obj2.getTimeInterval())
             newObject = MovingObject(newNum, newTimeInterval, nObjects = 1) # hypothesis is that it's the same object being reunited
+            newFeature = None
             if hasattr(obj1, 'featureNumbers') and hasattr(obj2, 'featureNumbers'):
                 newObject.featureNumbers = obj1.featureNumbers+obj2.featureNumbers
             if obj1.hasFeatures() and obj2.hasFeatures():
@@ -1376,7 +1382,7 @@
         if obj1.getUserType() != obj2.getUserType():
             print('The two moving objects have different user types: obj1 {} obj2 {}'.format(userTypeNames[obj1.getUserType()], userTypeNames[obj2.getUserType()]))
         newObject.setUserType(obj1.getUserType())
-        return newObject
+        return newObject, newFeature
 
     def getObjectInTimeInterval(self, inter):
         '''Returns a new object extracted from self,
--- a/trafficintelligence/storage.py	Thu Feb 17 10:55:11 2022 -0500
+++ b/trafficintelligence/storage.py	Thu Mar 24 16:07:51 2022 -0400
@@ -1479,8 +1479,8 @@
     '''Loads information from configuration file
     then checks what was passed on the command line
     for override (eg video filename and database filename'''
-    parentPath = Path(args.configFilename).parent
     if args.configFilename is not None: # consider there is a configuration file
+        parentPath = Path(args.configFilename).parent
         params = ProcessParameters(args.configFilename)
         videoFilename = params.videoFilename
         databaseFilename = params.databaseFilename
@@ -1494,6 +1494,7 @@
         undistort = params.undistort
         firstFrameNum = params.firstFrameNum
     else:
+        params = None
         invHomography = None
         undistort = False
         intrinsicCameraMatrix = None
--- a/trafficintelligence/tests/moving.txt	Thu Feb 17 10:55:11 2022 -0500
+++ b/trafficintelligence/tests/moving.txt	Thu Mar 24 16:07:51 2022 -0400
@@ -137,6 +137,9 @@
 >>> t3 = Trajectory.fromPointList([(92.2, 102.9), (56.7, 69.6), (56.7, 69.6)])
 >>> t1 == t3
 False
+>>> t1.append(t2)
+>>> t1.length()
+4
 
 >>> left = Trajectory.fromPointList([(92.291666666666686, 102.99239033124439), (56.774193548387103, 69.688898836168306)])
 >>> middle = Trajectory.fromPointList([(87.211021505376351, 93.390778871978512), (59.032258064516128, 67.540286481647257)])
@@ -151,8 +154,8 @@
 >>> Trajectory().length()
 0
 >>> t1 = Trajectory([[0.5,1.5,2.5],[0.5,3.5,6.5]])
->>> t1.length() == 3.
-True
+>>> t1.length()
+3
 >>> t1[1]
 (1.500000,3.500000)
 
@@ -298,9 +301,15 @@
 >>> o2.features = [o2]
 >>> o3 = MovingObject.generate(3, Point(2., 2.), Point(1., 1.), TimeInterval(2,12))
 >>> o3.features = [o3]
->>> o13 = MovingObject.concatenate(o1, o3, 4)
->>> o13.getNum()
-4
+>>> o4 = MovingObject.generate(4, Point(4., 4.), Point(1., 1.), TimeInterval(11,20))
+>>> o4.features = [o4]
+>>> o5 = MovingObject.generate(5, Point(5., 5.), Point(1., 1.), TimeInterval(12,22))
+>>> o5.features = [o5]
+
+>>> objNum = 14
+>>> o13, f13 = MovingObject.concatenate(o1, o3, objNum)
+>>> o13.getNum() == objNum
+True
 >>> o13.getTimeInterval() == TimeInterval(0,12)
 True
 >>> t=5
@@ -309,7 +318,7 @@
 >>> len(o13.getFeatures())
 2
 
->>> o12 = MovingObject.concatenate(o1, o2, 5, minFeatureLength = 6)
+>>> o12, f12 = MovingObject.concatenate(o1, o2, 15, 15)
 >>> o12.getTimeInterval() == TimeInterval(o1.getFirstInstant(), o2.getLastInstant())
 True
 >>> v = o12.getVelocityAtInstant(12)
@@ -319,9 +328,41 @@
 True
 >>> len(o12.getFeatures())
 3
->>> f = o12.getFeatures()[-1]
->>> f.length()
-6.0
+>>> f12.length()
+5.0
+>>> f12.getPositions().length()
+5
+>>> f12.getVelocities().length()
+5
+
+>>> o14, f14 = MovingObject.concatenate(o1, o4, 16)
+>>> len(o14.getFeatures())
+2
+>>> o14.getPositionAtInstant(10) == o1.getPositionAtInstant(10)
+True
+>>> o14.getPositionAtInstant(11) == o4.getPositionAtInstant(11)
+True
+
+>>> o15, f15 = MovingObject.concatenate(o1, o5, 17, 17)
+>>> len(o15.getFeatures())
+3
+>>> f15.length()
+3.0
+>>> o15.getFeatures()[-1] == f15
+True
+>>> o1.getPositionAtInstant(10) == o15.getPositionAtInstant(10)
+True
+>>> f15.getPositionAtInstant(11) == o15.getPositionAtInstant(11)
+True
+>>> o5.getPositionAtInstant(12) == o15.getPositionAtInstant(12)
+True
+>>> o15.updatePositions()
+>>> o1.getPositionAtInstant(10) == o15.getPositionAtInstant(10)
+True
+>>> f15.getPositionAtInstant(11) == o15.getPositionAtInstant(11)
+True
+>>> o5.getPositionAtInstant(12) == o15.getPositionAtInstant(12)
+True
 
 >>> o1 = MovingObject.generate(1, Point(0., 2.), Point(0., 1.), TimeInterval(0,2))
 >>> o1.classifyUserTypeSpeedMotorized(0.5, np.median)