changeset 1249:2aa56b101041

added mask functionality for dltrack
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Thu, 15 Feb 2024 14:09:52 -0500
parents c4c50678c856
children 77fbd0e2ba7d
files scripts/compute-clearmot.py scripts/dltrack.py scripts/undistort-video.py trafficintelligence/moving.py trafficintelligence/storage.py
diffstat 5 files changed, 48 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/compute-clearmot.py	Thu Feb 15 14:09:23 2024 -0500
+++ b/scripts/compute-clearmot.py	Thu Feb 15 14:09:52 2024 -0500
@@ -45,9 +45,9 @@
 if args.maskFilename is not None:
     maskObjects = []
     from matplotlib.pyplot import imread
-    mask = imread(args.maskFilename)
-    if len(mask) > 1:
-        mask = mask[:,:,0]
+    mask = imread(args.maskFilename, cv2.IMREAD_GRAYSCALE)
+    #if len(mask) > 1: if loaded as RGB
+    #    mask = mask[:,:,0]
     for obj in objects:
         maskObjects += obj.getObjectsInMask(mask, invHomography, 10) # TODO add option to keep object if at least one feature in mask
     objects = maskObjects
--- a/scripts/dltrack.py	Thu Feb 15 14:09:23 2024 -0500
+++ b/scripts/dltrack.py	Thu Feb 15 14:09:52 2024 -0500
@@ -26,14 +26,14 @@
 parser.add_argument('-m', dest = 'detectorFilename', help = 'name of the detection model file', required = True)
 parser.add_argument('-t', dest = 'trackerFilename', help = 'name of the tracker file', required = True)
 parser.add_argument('-o', dest = 'homographyFilename', help = 'filename of the homography matrix')
-#parser.add_argument('-k', dest = 'maskFilename', help = 'name of the mask file')
+parser.add_argument('-k', dest = 'maskFilename', help = 'name of the mask file')
 parser.add_argument('--undistort', dest = 'undistort', help = 'undistort the video', action = 'store_true')
 parser.add_argument('--intrinsic', dest = 'intrinsicCameraMatrixFilename', help = 'name of the intrinsic camera file')
 parser.add_argument('--distortion-coefficients', dest = 'distortionCoefficients', help = 'distortion coefficients', nargs = '*', type = float)
 parser.add_argument('--display', dest = 'display', help = 'show the raw detection and tracking results', action = 'store_true')
 parser.add_argument('--no-image-coordinates', dest = 'notSavingImageCoordinates', help = 'not saving the raw detection and tracking results', action = 'store_true')
 parser.add_argument('-f', dest = 'firstFrameNum', help = 'number of first frame number to process', type = int, default = 0)
-parser.add_argument('-l', dest = 'lastFrameNum', help = 'number of last frame number to process', type = int, default = float('Inf'))
+parser.add_argument('-l', dest = 'lastFrameNum', help = 'number of last frame number to process', type = int, default = inf)
 parser.add_argument('--conf', dest = 'confidence', help = 'object confidence threshold for detection', type = float, default = 0.25)
 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)
@@ -56,7 +56,13 @@
 elif args.configFilename is not None:
     lastFrameNum = params.lastFrameNum
 else:
-    lastFrameNum = inf
+    lastFrameNum = args.lastFrameNum
+if args.maskFilename is not None:
+    mask = cv2.imread(args.maskFilename, cv2.IMREAD_GRAYSCALE)
+elif params.maskFilename is not None:
+    mask = cv2.imread(params.maskFilename, cv2.IMREAD_GRAYSCALE)
+else:
+    mask = None
 
 # TODO use mask, remove short objects, smooth
 
@@ -86,32 +92,37 @@
     print('Input {} could not be read. Exiting'.format(args.videoFilename))
     import sys; sys.exit()
 
-results = model.track(frame, tracker=args.trackerFilename, classes=list(moving.cocoTypeNames.keys()), conf = args.confidence, persist=True, verbose=False)
+results = model.track(source=frame, tracker=args.trackerFilename, classes=list(moving.cocoTypeNames.keys()), conf=args.confidence, persist=True, verbose=False)
 while capture.isOpened() and success and frameNum <= lastFrameNum:
     result = results[0]
     if frameNum %10 == 0:
         print(frameNum, len(result.boxes), 'objects')
     for box in result.boxes:
-        if box.id is not None: # None are objects with low confidence
-            num = int(box.id.item())
-            if num in objects:
-                objects[num].timeInterval.last = frameNum
-                objects[num].features[0].timeInterval.last = frameNum
-                objects[num].features[1].timeInterval.last = frameNum
-                objects[num].bboxes[frameNum] = copy(box.xyxy)
-                objects[num].userTypes.append(moving.coco2Types[int(box.cls.item())])
-                objects[num].features[0].tmpPositions[frameNum] = moving.Point(box.xyxy[0,0].item(), box.xyxy[0,1].item()) # min
-                objects[num].features[1].tmpPositions[frameNum] = moving.Point(box.xyxy[0,2].item(), box.xyxy[0,3].item()) # max
-            else:
-                inter = moving.TimeInterval(frameNum, frameNum)
-                objects[num] = moving.MovingObject(num, inter)
-                objects[num].bboxes = {frameNum: copy(box.xyxy)}
-                objects[num].userTypes = [moving.coco2Types[int(box.cls.item())]]
-                objects[num].features = [moving.MovingObject(featureNum, copy(inter)), moving.MovingObject(featureNum+1, copy(inter))]
-                objects[num].featureNumbers = [featureNum, featureNum+1]
-                objects[num].features[0].tmpPositions = {frameNum: moving.Point(box.xyxy[0,0].item(), box.xyxy[0,1].item())}
-                objects[num].features[1].tmpPositions = {frameNum: moving.Point(box.xyxy[0,2].item(), box.xyxy[0,3].item())}
-                featureNum += 2
+        if box.id is not None:# None are objects with low confidence
+            xyxy = copy(box.xyxy)
+            minPoint = moving.Point(xyxy[0,0].item(), xyxy[0,1].item())
+            maxPoint = moving.Point(xyxy[0,2].item(), xyxy[0,3].item())
+            center = (minPoint+maxPoint).divide(2.).asint()
+            if mask is None or mask[center.y, center.x] > 0:
+                num = int(box.id.item())
+                if num in objects:
+                    objects[num].timeInterval.last = frameNum
+                    objects[num].features[0].timeInterval.last = frameNum
+                    objects[num].features[1].timeInterval.last = frameNum
+                    objects[num].bboxes[frameNum] = xyxy
+                    objects[num].userTypes.append(moving.coco2Types[int(box.cls.item())])
+                    objects[num].features[0].tmpPositions[frameNum] = minPoint # min
+                    objects[num].features[1].tmpPositions[frameNum] = maxPoint # max
+                else:
+                    inter = moving.TimeInterval(frameNum, frameNum)
+                    objects[num] = moving.MovingObject(num, inter)
+                    objects[num].bboxes = {frameNum: copy(xyxy)}
+                    objects[num].userTypes = [moving.coco2Types[int(box.cls.item())]]
+                    objects[num].features = [moving.MovingObject(featureNum, copy(inter)), moving.MovingObject(featureNum+1, copy(inter))]
+                    objects[num].featureNumbers = [featureNum, featureNum+1]
+                    objects[num].features[0].tmpPositions = {frameNum: minPoint}
+                    objects[num].features[1].tmpPositions = {frameNum: maxPoint}
+                    featureNum += 2
     if args.display:
         cvutils.cvImshow(windowName, result.plot()) # original image in orig_img
         key = cv2.waitKey()
@@ -119,7 +130,9 @@
             break
     frameNum += 1
     success, frame = capture.read()
-    results = model.track(frame, persist=True)
+    results = model.track(source=frame, persist=True)
+capture.release()
+cv2.destroyAllWindows()
 
 # classification
 for num, obj in objects.items():
@@ -221,10 +234,7 @@
     else:
         t = []
         for instant in obj.getTimeInterval():
-            points = []
-            for f in features:
-                if f.existsAtInstant(instant):
-                    points.append(f.getPositionAtInstant(instant))
+            points = [f.getPositionAtInstant(instant) for f in features if f.existsAtInstant(instant)]
             t.append(moving.Point.agg(points, np.mean).aslist())
         #t = sum([f.getPositions().asArray() for f in features])/len(features)
         #t = (moving.Trajectory.add(t1, t2)*0.5).asArray()
--- a/scripts/undistort-video.py	Thu Feb 15 14:09:23 2024 -0500
+++ b/scripts/undistort-video.py	Thu Feb 15 14:09:52 2024 -0500
@@ -39,7 +39,7 @@
 height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
 [map1, map2], newCameraMatrix = cvutils.computeUndistortMaps(width, height, args.undistortedImageMultiplication, intrinsicCameraMatrix, args.distortionCoefficients)
 if args.maskFilename is not None:
-    mask = cv2.imread(args.maskFilename)
+    mask = cv2.imread(args.maskFilename, cv2.IMREAD_GRAYSCALE)
     undistortedMask = cv2.remap(mask, map1, map2, interpolation=cv2.INTER_LINEAR)/255
 
 if capture.isOpened():
--- a/trafficintelligence/moving.py	Thu Feb 15 14:09:23 2024 -0500
+++ b/trafficintelligence/moving.py	Thu Feb 15 14:09:52 2024 -0500
@@ -2,7 +2,7 @@
 '''Libraries for moving objects, trajectories...'''
 
 import copy
-from math import sqrt, atan2, cos, sin
+from math import sqrt, atan2, cos, sin, inf
 
 from numpy import median, mean, array, arange, zeros, ones, hypot, NaN, std, floor, ceil, float32, argwhere, minimum,  issubdtype, integer as npinteger, percentile
 from matplotlib.pyplot import plot, text, arrow
@@ -295,7 +295,7 @@
         return (self.x, self.y)
 
     def asint(self):
-        return Point(int(self.x), int(self.y))
+        return Point(int(round(self.x)), int(round(self.y)))
 
     if shapelyAvailable:
         def asShapely(self):
@@ -2054,7 +2054,7 @@
         self.setUserType(utils.argmaxDict(userTypeProbabilities))
         return userTypeProbabilities
 
-    def initClassifyUserTypeHoGSVM(self, aggregationFunc, pedBikeCarSVM, bikeCarSVM = None, pedBikeSpeedThreshold = float('Inf'), bikeCarSpeedThreshold = float('Inf'), nInstantsIgnoredAtEnds = 0, homography = None, intrinsicCameraMatrix = None, distortionCoefficients = None):
+    def initClassifyUserTypeHoGSVM(self, aggregationFunc, pedBikeCarSVM, bikeCarSVM = None, pedBikeSpeedThreshold = inf, bikeCarSpeedThreshold = float('Inf'), nInstantsIgnoredAtEnds = 0, homography = None, intrinsicCameraMatrix = None, distortionCoefficients = None):
         '''Initializes the data structures for classification
 
         TODO? compute speed for longest feature?'''
--- a/trafficintelligence/storage.py	Thu Feb 15 14:09:23 2024 -0500
+++ b/trafficintelligence/storage.py	Thu Feb 15 14:09:52 2024 -0500
@@ -1610,6 +1610,8 @@
         distortionCoefficients = getValuesFromINIFile(filename, 'distortion-coefficients', '=')        
         self.distortionCoefficients = [float(x) for x in distortionCoefficients]
         self.undistortedImageMultiplication  = config.getfloat(self.sectionHeader, 'undistorted-size-multiplication')
+        self.maskFilename = utils.getRelativeFilename(parentPath, config.get(self.sectionHeader, 'mask-filename'))
+      
         self.undistort = config.getboolean(self.sectionHeader, 'undistort')
         self.firstFrameNum = config.getint(self.sectionHeader, 'frame1')
         self.videoFrameRate = config.getfloat(self.sectionHeader, 'video-fps')