changeset 1250:77fbd0e2ba7d

dltrack works with moving average filtering
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Thu, 15 Feb 2024 22:04:35 -0500
parents 2aa56b101041
children 2b1c8fe8f7e4
files scripts/dltrack.py trafficintelligence/moving.py trafficintelligence/storage.py trafficintelligence/tests/utils.txt trafficintelligence/utils.py
diffstat 5 files changed, 42 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/dltrack.py	Thu Feb 15 14:09:52 2024 -0500
+++ b/scripts/dltrack.py	Thu Feb 15 22:04:35 2024 -0500
@@ -59,10 +59,14 @@
     lastFrameNum = args.lastFrameNum
 if args.maskFilename is not None:
     mask = cv2.imread(args.maskFilename, cv2.IMREAD_GRAYSCALE)
-elif params.maskFilename is not None:
+elif params is not None and params.maskFilename is not None:
     mask = cv2.imread(params.maskFilename, cv2.IMREAD_GRAYSCALE)
 else:
     mask = None
+if params is not None:
+    smoothingHalfWidth = params.smoothingHalfWidth
+else:
+    smoothingHalfWidth = None
 
 # TODO use mask, remove short objects, smooth
 
@@ -135,9 +139,14 @@
 cv2.destroyAllWindows()
 
 # classification
+shortObjectNumbers = []
 for num, obj in objects.items():
-    obj.setUserType(utils.mostCommon(obj.userTypes)) # improve? mix with speed?
-
+    if obj.length() < 3:
+        shortObjectNumbers.append(num)
+    else:
+        obj.setUserType(utils.mostCommon(obj.userTypes)) # improve? mix with speed?
+for num in shortObjectNumbers:
+    del objects[num]
 # TODO add quality control: avoid U-turns
     
 # merge bikes and people
@@ -242,8 +251,14 @@
     featureNum = features[0].getNum()
     obj.features=[moving.MovingObject(featureNum, obj.getTimeInterval(), moving.Trajectory(projected.tolist()))]
     obj.featureNumbers = [featureNum]
+if smoothingHalfWidth is not None: # smoothing
+    for num, obj in objects.items():
+        for f in obj.getFeatures():
+            f.positions = f.getPositions().filterMovingWindow(smoothingHalfWidth)
 storage.saveTrajectoriesToSqlite(args.databaseFilename, list(objects.values()), 'object')
 
+
+
 # todo save bbox and mask to study localization / representation
 # apply quality checks deviation and acceleration bounds?
 
--- a/trafficintelligence/moving.py	Thu Feb 15 14:09:52 2024 -0500
+++ b/trafficintelligence/moving.py	Thu Feb 15 22:04:35 2024 -0500
@@ -990,10 +990,10 @@
         return Trajectory([[alpha*x for x in self.getXCoordinates()],
                            [alpha*y for y in self.getYCoordinates()]])
 
-    def filterMovingWindow(self, halfWidth, mode = 'valid'):
+    def filterMovingWindow(self, halfWidth):
         '''Returns a new Trajectory obtained after the smoothing of the input by a moving average'''
-        return Trajectory([utils.filterMovingWindow(self.positions[0], halfWidth, mode),
-                           utils.filterMovingWindow(self.positions[1], halfWidth, mode)])
+        return Trajectory([utils.filterMovingWindow(self.positions[0], halfWidth),
+                           utils.filterMovingWindow(self.positions[1], halfWidth)])
 
     def differentiate(self, doubleLastPosition = False):
         diff = Trajectory()
--- a/trafficintelligence/storage.py	Thu Feb 15 14:09:52 2024 -0500
+++ b/trafficintelligence/storage.py	Thu Feb 15 22:04:35 2024 -0500
@@ -1654,7 +1654,7 @@
         self.minFeatureEigThreshold = config.getfloat(self.sectionHeader, 'min-feature-eig-threshold')
         self.minFeatureTime = config.getint(self.sectionHeader, 'min-feature-time')
         self.minFeatureDisplacement = config.getfloat(self.sectionHeader, 'min-feature-displacement')
-        self.smoothingHalfWidth = config.getfloat(self.sectionHeader, 'smoothing-halfwidth')
+        self.smoothingHalfWidth = config.getint(self.sectionHeader, 'smoothing-halfwidth')
         #self.updateTimer = config.getint(self.sectionHeader, 'tracker-reload-time')
         
 
--- a/trafficintelligence/tests/utils.txt	Thu Feb 15 14:09:52 2024 -0500
+++ b/trafficintelligence/tests/utils.txt	Thu Feb 15 22:04:35 2024 -0500
@@ -1,5 +1,6 @@
 >>> from trafficintelligence.utils import *
 >>> from trafficintelligence.moving import Point
+>>> from numpy import array, arange
 
 >>> upperCaseFirstLetter('mmmm... donuts')
 'Mmmm... Donuts'
@@ -46,6 +47,15 @@
 >>> values[-1]
 6.0
 
+>>> filterMovingWindow(arange(10), 3)
+array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
+>>> filterMovingWindow(list(range(10)), 3)
+array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
+>>> filterMovingWindow(arange(10.), 3)
+array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
+>>> filterMovingWindow(arange(10.), 2)
+array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
+
 >>> stepPlot([3, 5, 7, 8], 1, 10, 0)
 ([1, 3, 3, 5, 5, 7, 7, 8, 8, 10], [0, 0, 1, 1, 2, 2, 3, 3, 4, 4])
 
--- a/trafficintelligence/utils.py	Thu Feb 15 14:09:52 2024 -0500
+++ b/trafficintelligence/utils.py	Thu Feb 15 22:04:35 2024 -0500
@@ -11,7 +11,7 @@
 from scipy.stats import rv_continuous, kruskal, shapiro, lognorm, norm, t, chi2_contingency
 from scipy.spatial import distance
 from scipy.sparse import dok_matrix
-from numpy import zeros, array, exp, sum as npsum, int64 as npint, arange, cumsum, mean, median, percentile, isnan, ones, convolve,  dtype, isnan, NaN, ma, isinf, savez, load as npload, log, polyfit
+from numpy import zeros, array, exp, sum as npsum, int64 as npint, arange, cumsum, mean, median, percentile, isnan, ones, convolve,  dtype, isnan, NaN, ma, isinf, savez, load as npload, log, polyfit, float64
 from numpy.random import random_sample, permutation as nppermutation
 from pandas import DataFrame, concat, crosstab
 import matplotlib.pyplot as plt
@@ -431,13 +431,18 @@
         smoothed[point] = max(set(window_values), key=window_values.count)
     return smoothed
 
-def filterMovingWindow(inputSignal, halfWidth, mode = 'valid'):
+def filterMovingWindow(inputSignal, halfWidth):
     '''Returns an array obtained after the smoothing of the 1-D input by a moving average
     The size of the output depends on the mode: 'full', 'same', 'valid'
     See https://numpy.org/doc/stable/reference/generated/numpy.convolve.html.'''
-    width = min(len(inputSignal), int(halfWidth*2+1))
-    win = ones(width,'d')
-    return convolve(win/width, array(inputSignal), mode)
+    halfWidth = min(floor((len(inputSignal)-1)/2.), halfWidth)
+    win = ones(2*halfWidth+1)/(2*halfWidth+1)
+    filtered = array(inputSignal, dtype=float64)
+    filtered[halfWidth:-halfWidth] = convolve(inputSignal, win, 'valid') # .ravel()
+    for i in range(halfWidth-1):
+        filtered[i] = sum(inputSignal[:2*i+1])/(2*i+1)
+        filtered[-1-i] = sum(inputSignal[-1-2*i:])/(2*i+1)
+    return filtered
 
 def linearRegression(x, y, deg = 1, plotData = False):
     '''returns the least square estimation of the linear regression of y = ax+b