Mercurial Hosting > traffic-intelligence
changeset 1237:31a441efca6c
ped-bike grouping working, bike merging left todo
author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
---|---|
date | Mon, 02 Oct 2023 16:51:43 -0400 |
parents | 100fe098abe9 |
children | b684135d817f |
files | scripts/dltrack.py |
diffstat | 1 files changed, 53 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/dltrack.py Tue Sep 19 17:04:30 2023 -0400 +++ b/scripts/dltrack.py Mon Oct 02 16:51:43 2023 -0400 @@ -3,9 +3,11 @@ import sys, argparse from copy import copy from collections import Counter +import numpy as np +from scipy.optimize import linear_sum_assignment from ultralytics import YOLO from torch import cat -from torchvision import ops +from torchvision.ops import box_iou import cv2 from trafficintelligence import cvutils, moving, storage, utils @@ -18,7 +20,10 @@ parser.add_argument('--display', dest = 'display', help = 'show the results (careful with long videos, risk of running out of memory)', 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('--bike-pct', dest = 'bikeProportion', help = 'percent of time a person classified as bike or motorbike to be classified as cyclist', type = float, default = 0.2) +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) +# mask!! args = parser.parse_args() # required functionality? @@ -65,7 +70,7 @@ # check if one can go to specific frame https://docs.ultralytics.com/modes/track/#persisting-tracks-loop # Load a model -model = YOLO(args.detectorFilename, ) # seg yolov8x-seg.pt +model = YOLO(args.detectorFilename) # seg yolov8x-seg.pt # seg could be used on cropped image... if can be loaded and kept in memory # model = YOLO('/home/nicolas/Research/Data/classification-models/yolo_nas_l.pt ') # AttributeError: 'YoloNAS_L' object has no attribute 'get' @@ -85,7 +90,7 @@ lastFrameNum = args.lastFrameNum success, frame = capture.read() -results = model.track(frame, tracker=args.trackerFilename, classes=list(moving.cocoTypeNames.keys()), persist=True) +results = model.track(frame, tracker=args.trackerFilename, classes=list(moving.cocoTypeNames.keys()), persist=True, verbose=False) # create object with user type and list of 3 features (bottom ones and middle) + projection while capture.isOpened() and success and frameNum <= lastFrameNum: #for frameNum, result in enumerate(results): @@ -131,12 +136,51 @@ obj.setUserType(userTypeStats.most_common()[0][0]) # merge bikes and people -#Construire graphe bipartite vélo/moto personne -#Lien = somme des iou / longueur track vélo -#Algo Hongrois -#Verif overlap piéton vélo : si long, changement mode (trouver exemples) +twowheels = [num for num, obj in currentObjects.items() if obj.getUserType() in (3,4)] +pedestrians = [num for num, obj in currentObjects.items() if obj.getUserType() == 2] + +costs = [] +for twInd in twowheels: + tw = currentObjects[twInd] + twCost = [] + for pedInd in pedestrians: + ped = currentObjects[pedInd] + nmatches = 0 + for t in tw.bboxes: + if t in ped.bboxes: + #print(tw.num, ped.num, t, box_iou(tw.bboxes[t], ped.bboxes[t])) + if box_iou(tw.bboxes[t], ped.bboxes[t]).item() > args.cyclistIou: + nmatches += 1 + twCost.append(nmatches/len(tw.bboxes)) + costs.append(twCost) -# for all cyclists and motorbikes +costs = -np.array(costs) +# before matching, scan for pedestrians with good non-overlapping temporal match with different bikes +for pedInd in costs.shape[1]: + if sum(costs[:,pedInd] < -args.cyclistMatchingProportion) >1: + twIndices = np.nonzero(costs[:,pedInd] < -args.cyclistMatchingProportion) + # we have to compute temporal overlaps with everyone else, then remove the ones with the most overlap (sum over column) one by one until there is little left + temporalOverlaps = np.zeros((len(twIndices),len(twIndices))) + + +twIndices, matchingPedIndices = linear_sum_assignment(costs) +for twInd, pedInd in zip(twIndices, matchingPedIndices): # caution indices in the cost matrix + if -costs[twInd, pedInd] >= args.cyclistMatchingProportion: + tw = currentObjects[twowheels[twInd]] + ped = currentObjects[pedestrians[pedInd]] + timeInstants = set(tw.bboxes).union(set(ped.bboxes)) + for t in timeInstants: + if t in tw.bboxes and t in ped.bboxes: + tw.features[0].tmpPositions[t] = moving.Point(min(tw.features[0].tmpPositions[t].x, ped.features[0].tmpPositions[t].x), + min(tw.features[0].tmpPositions[t].y, ped.features[0].tmpPositions[t].y)) + tw.features[1].tmpPositions[t] = moving.Point(max(tw.features[1].tmpPositions[t].x, ped.features[1].tmpPositions[t].x), + max(tw.features[1].tmpPositions[t].y, ped.features[1].tmpPositions[t].y)) + elif t in ped.bboxes: + tw.features[0].tmpPositions[t] = ped.features[0].tmpPositions[t] + tw.features[1].tmpPositions[t] = ped.features[1].tmpPositions[t] + tw.timeInterval = moving.TimeInterval(min(tw.getFirstInstant(), ped.getFirstInstant()), max(tw.getLastInstant(), ped.getLastInstant())) + del currentObjects[pedestrians[pedInd]] +#Verif overlap piéton vélo : si long hors overlap, changement mode (trouver exemples) # interpolate and generate velocity (?) before saving for num, obj in currentObjects.items():