changeset 1271:b2f90cada58f

removed complex merging of bikes and peds, may result in more fragmentation
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Fri, 14 Jun 2024 15:56:01 -0400
parents 20a5e1292321
children 785c86013d2c 655a1646f0d5
files scripts/dltrack.py
diffstat 1 files changed, 45 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/dltrack.py	Mon Jun 10 16:44:19 2024 -0400
+++ b/scripts/dltrack.py	Fri Jun 14 15:56:01 2024 -0400
@@ -38,7 +38,7 @@
 parser.add_argument('--bike-prop', dest = 'bikeProportion', help = 'minimum proportion of time a person classified as bike or motorbike to be classified as cyclist', type = float, default = 0.2)
 parser.add_argument('--cyclist-iou', dest = 'cyclistIou', help = 'IoU threshold to associate a bike and ped bounding box', type = float, default = 0.15)
 parser.add_argument('--cyclist-match-prop', dest = 'cyclistMatchingProportion', help = 'minimum proportion of time a bike exists and is associated with a pedestrian to be merged as cyclist', type = float, default = 0.3)
-parser.add_argument('--max-temp-overal', dest = 'maxTemporalOverlap', help = 'maximum proportion of time to merge 2 bikes associated with same pedestrian', type = float, default = 0.05)
+#parser.add_argument('--max-temp-overal', dest = 'maxTemporalOverlap', help = 'maximum proportion of time to merge 2 bikes associated with same pedestrian', type = float, default = 0.05)
 
 args = parser.parse_args()
 params, videoFilename, databaseFilename, homography, invHomography, intrinsicCameraMatrix, distortionCoefficients, undistortedImageMultiplication, undistort, firstFrameNum = storage.processVideoArguments(args)
@@ -65,8 +65,10 @@
     mask = None
 if params is not None:
     smoothingHalfWidth = params.smoothingHalfWidth
+    minObjectDuration = params.minFeatureTime
 else:
     smoothingHalfWidth = None
+    minObjectDuration = 3
 
 # TODO use mask, remove short objects, smooth
 
@@ -142,7 +144,7 @@
 # classification
 shortObjectNumbers = []
 for num, obj in objects.items():
-    if obj.length() < 3:
+    if obj.length() < minObjectDuration:
         shortObjectNumbers.append(num)
     else:
         obj.setUserType(utils.mostCommon(obj.userTypes)) # improve? mix with speed?
@@ -181,39 +183,39 @@
 # before matching, scan for pedestrians with good non-overlapping temporal match with different bikes
     for pedInd in range(costs.shape[1]):
         nMatchedBikes = (costs[:,pedInd] < -args.cyclistMatchingProportion).sum()
-        if nMatchedBikes == 0: # peds that have no bike matching: see if they have been classified as bikes sometimes
+        if nMatchedBikes == 0: # peds that have no bike matching: see if they have been classified as bikes sometimes (more than args.bikeProportion)
             userTypeStats = Counter(obj.userTypes)
             if (moving.userType2Num['cyclist'] in userTypeStats or (moving.userType2Num['motorcyclist'] in userTypeStats and moving.userType2Num['cyclist'] in userTypeStats and userTypeStats[moving.userType2Num['motorcyclist']]<=userTypeStats[moving.userType2Num['cyclist']])) and userTypeStats[moving.userType2Num['motorcyclist']]+userTypeStats[moving.userType2Num['cyclist']] > args.bikeProportion*userTypeStats.total(): # verif if not turning all motorbike into cyclists
                 obj.setUserType(moving.userType2Num['cyclist'])
-        elif nMatchedBikes > 1: # try to merge bikes first
-            twIndices = np.nonzero(costs[:,pedInd] < -args.cyclistMatchingProportion)[0]
-            # we have to compute temporal overlaps of all 2 wheels among themselves, then remove the ones with the most overlap (sum over column) one by one until there is little left
-            nTwoWheels = len(twIndices)
-            twTemporalOverlaps = np.zeros((nTwoWheels,nTwoWheels))
-            for i in range(nTwoWheels):
-                for j in range(i):
-                    twi = objects[twowheels[twIndices[i]]]
-                    twj = objects[twowheels[twIndices[j]]]
-                    twTemporalOverlaps[i,j] = len(set(twi.bboxes).intersection(set(twj.bboxes)))/max(len(twi.bboxes), len(twj.bboxes))
-                    #twTemporalOverlaps[j,i] = twTemporalOverlaps[i,j]
-            tw2merge = list(range(nTwoWheels))
-            while len(tw2merge)>0 and (twTemporalOverlaps[np.ix_(tw2merge, tw2merge)] > args.maxTemporalOverlap).sum(0).max() >= 2:
-                i = (twTemporalOverlaps[np.ix_(tw2merge, tw2merge)] > args.maxTemporalOverlap).sum(0).argmax()
-                del tw2merge[i]
-            twIndices = [twIndices[i] for i in tw2merge]
-            tw1 = objects[twowheels[twIndices[0]]]
-            twCost = costs[twIndices[0],:]*tw1.nBBoxes
-            nBBoxes = tw1.nBBoxes
-            for twInd in twIndices[1:]:
-                mergeObjects(tw1, objects[twowheels[twInd]])
-                twCost = twCost + costs[twInd,:]*objects[twowheels[twInd]].nBBoxes
-                nBBoxes += objects[twowheels[twInd]].nBBoxes
-            twIndicesToKeep = list(range(costs.shape[0]))
-            for twInd in twIndices[1:]:
-                twIndicesToKeep.remove(twInd)
-                del objects[twowheels[twInd]]
-            twowheels = [twowheels[i] for i in twIndicesToKeep]
-            costs = costs[twIndicesToKeep,:]
+        # elif nMatchedBikes > 1: # try to merge bikes first
+        #     twIndices = np.nonzero(costs[:,pedInd] < -args.cyclistMatchingProportion)[0]
+        #     # we have to compute temporal overlaps of all 2 wheels among themselves, then remove the ones with the most overlap (sum over column) one by one until there is little left
+        #     nTwoWheels = len(twIndices)
+        #     twTemporalOverlaps = np.zeros((nTwoWheels,nTwoWheels))
+        #     for i in range(nTwoWheels):
+        #         for j in range(i):
+        #             twi = objects[twowheels[twIndices[i]]]
+        #             twj = objects[twowheels[twIndices[j]]]
+        #             twTemporalOverlaps[i,j] = len(set(twi.bboxes).intersection(set(twj.bboxes)))/max(len(twi.bboxes), len(twj.bboxes))
+        #             #twTemporalOverlaps[j,i] = twTemporalOverlaps[i,j]
+        #     tw2merge = list(range(nTwoWheels))
+        #     while len(tw2merge)>0 and (twTemporalOverlaps[np.ix_(tw2merge, tw2merge)] > args.maxTemporalOverlap).sum(0).max() >= 2:
+        #         i = (twTemporalOverlaps[np.ix_(tw2merge, tw2merge)] > args.maxTemporalOverlap).sum(0).argmax()
+        #         del tw2merge[i]
+        #     twIndices = [twIndices[i] for i in tw2merge]
+        #     tw1 = objects[twowheels[twIndices[0]]]
+        #     twCost = costs[twIndices[0],:]*tw1.nBBoxes
+        #     nBBoxes = tw1.nBBoxes
+        #     for twInd in twIndices[1:]:
+        #         mergeObjects(tw1, objects[twowheels[twInd]])
+        #         twCost = twCost + costs[twInd,:]*objects[twowheels[twInd]].nBBoxes
+        #         nBBoxes += objects[twowheels[twInd]].nBBoxes
+        #     twIndicesToKeep = list(range(costs.shape[0]))
+        #     for twInd in twIndices[1:]:
+        #         twIndicesToKeep.remove(twInd)
+        #         del objects[twowheels[twInd]]
+        #     twowheels = [twowheels[i] for i in twIndicesToKeep]
+        #     costs = costs[twIndicesToKeep,:]
 
     twIndices, matchingPedIndices = linear_sum_assignment(costs)
     for twInd, pedInd in zip(twIndices, matchingPedIndices): # caution indices in the cost matrix
@@ -222,8 +224,11 @@
             ped = objects[pedestrians[pedInd]]
             mergeObjects(tw, ped)
             del objects[pedestrians[pedInd]]
+            # link ped to each assigned bike, remove bike from cost (and ped is temporal match is high)
+            
             #TODO Verif overlap piéton vélo : si long hors overlap, changement mode (trouver exemples)
-
+    # TODO continue assigning if leftover bikes (if non temporally overlapping with existing bikes assigned to ped)
+            
 # interpolate and save image coordinates
 for num, obj in objects.items():
     for f in obj.getFeatures():
@@ -233,7 +238,7 @@
             f.positions = moving.Trajectory.fromPointList(list(f.tmpPositions.values()))
 if not args.notSavingImageCoordinates:
     storage.saveTrajectoriesToSqlite(utils.removeExtension(args.databaseFilename)+'-bb.sqlite', list(objects.values()), 'object')
-# project, smooth and save
+# project and smooth
 for num, obj in objects.items():
     features = obj.getFeatures()
     # possible to save bottom pedestrians? not consistent with other users
@@ -251,13 +256,13 @@
     #t = (moving.Trajectory.add(t1, t2)*0.5).asArray()
     projected = cvutils.imageToWorldProject(np.array(t).T, intrinsicCameraMatrix, distortionCoefficients, homography)
     featureNum = features[0].getNum()
-    obj.features=[moving.MovingObject(featureNum, obj.getTimeInterval(), moving.Trajectory(projected.tolist()))]
+    feature = moving.MovingObject(featureNum, obj.getTimeInterval(), moving.Trajectory(projected.tolist()))
+    if smoothingHalfWidth is not None: # smoothing
+        feature.smoothPositions(smoothingHalfWidth, replace = True)#f.positions = f.getPositions().filterMovingWindow(smoothingHalfWidth)
+    feature.computeVelocities()
+    obj.features=[feature]
     obj.featureNumbers = [featureNum]
-if smoothingHalfWidth is not None: # smoothing
-    for num, obj in objects.items():
-        for f in obj.getFeatures():
-            f.smoothPositions(smoothingHalfWidth, replace = True)#f.positions = f.getPositions().filterMovingWindow(smoothingHalfWidth)
-            f.computeVelocities()
+#saving
 storage.saveTrajectoriesToSqlite(args.databaseFilename, list(objects.values()), 'object')