nsaunier/traffic-intelligence
removed complex merging of bikes and peds, may result in more fragmentation
Commit b2f90cada58f · Nicolas Saunier · 2024-06-14 15:56 -0400
Comments
No comments yet.
Diff
diff --git a/scripts/dltrack.py b/scripts/dltrack.py
--- a/scripts/dltrack.py
+++ b/scripts/dltrack.py
@@ -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')