def __init__(self, max_age=30, nms_max_overlap=1.0, max_cosine_distance=0.2, nn_budget=None, override_track_class=None, clock=None, half=True): ''' Input Params: - nms_max_overlap: Non-maxima suppression threshold: Maximum detection overlap - max_cosine_distance: Gating threshold for cosine distance - nn_budget: Maximum size of the appearance descriptors, if None, no budget is enforced ''' print('Initialising DeepSort..') # self.video_info = video_info # assert clock is not None self.nms_max_overlap = nms_max_overlap metric = nn_matching.NearestNeighborDistanceMetric( "cosine", max_cosine_distance, nn_budget) self.tracker = Tracker(metric, max_age=max_age, override_track_class=override_track_class, clock=clock) self.embedder = Embedder(half=half) print('DeepSort Tracker initialised!')
def __init__(self, max_age = 30, nms_max_overlap=1.0, max_cosine_distance=0.2, nn_budget=None, override_track_class=None, clock=None, embedder=True, half=True, bgr=True, logger=None, polygon=False): ''' Parameters ---------- max_age : Optional[int] = 30 Maximum number of missed misses before a track is deleted. nms_max_overlap : Optional[float] = 1.0 Non-maxima suppression threshold: Maximum detection overlap, if is 1.0, nms will be disabled max_cosine_distance : Optional[float] = 0.2 Gating threshold for cosine distance nn_budget : Optional[int] = None Maximum size of the appearance descriptors, if None, no budget is enforced override_track_class : Optional[object] = None Giving this will override default Track class, this must inherit Track clock : Optional[object] = None Clock custom object provides date for track naming and facilitates track id reset every day, preventing overflow and overly large track ids. For example clock class, please see `utils/clock.py` embedder : Optional[bool] = True Whether to use in-built embedder or not. If False, then embeddings must be given during update half : Optional[bool] = True Whether to use half precision for deep embedder bgr : Optional[bool] = True Whether frame given to embedder is expected to be BGR or not (RGB) logger : Optional[object] = None logger object polygon: Optional[bool] = False Whether detections are polygons (e.g. oriented bounding boxes) ''' if logger is None: self.logger = default_logger else: self.logger = logger # self.video_info = video_info # assert clock is not None self.nms_max_overlap = nms_max_overlap metric = nn_matching.NearestNeighborDistanceMetric( "cosine", max_cosine_distance, nn_budget) self.tracker = Tracker(metric, max_age = max_age, override_track_class=override_track_class, clock=clock, logger=self.logger) if embedder: self.embedder = Embedder(half=half, max_batch_size=16, bgr=bgr) else: self.embedder = None self.polygon = polygon self.logger.info('DeepSort Tracker initialised') self.logger.info(f'- max age: {max_age}') self.logger.info(f'- appearance threshold: {max_cosine_distance}') self.logger.info(f'- nms threshold: {"OFF" if self.nms_max_overlap==1.0 else self.nms_max_overlap }') self.logger.info(f'- max num of appearance features: {nn_budget}') self.logger.info(f'- overriding track class : {"No" if override_track_class is None else "Yes"}' ) self.logger.info(f'- clock : {"No" if clock is None else "Yes"}' ) self.logger.info(f'- in-build embedder : {"No" if self.embedder is None else "Yes"}' ) self.logger.info(f'- polygon detections : {"No" if polygon is False else "Yes"}' )
class DeepSort(object): def __init__(self, max_age = 30, nms_max_overlap=1.0, max_cosine_distance=0.2, nn_budget=None, override_track_class=None, clock=None, half=True): ''' Input Params: - nms_max_overlap: Non-maxima suppression threshold: Maximum detection overlap - max_cosine_distance: Gating threshold for cosine distance - nn_budget: Maximum size of the appearance descriptors, if None, no budget is enforced ''' print('Initialising DeepSort..') # self.video_info = video_info # assert clock is not None self.nms_max_overlap = nms_max_overlap metric = nn_matching.NearestNeighborDistanceMetric( "cosine", max_cosine_distance, nn_budget) self.tracker = Tracker(metric, max_age = max_age, override_track_class=override_track_class, clock=clock) self.embedder = Embedder(half=half) print('DeepSort Tracker initialised!') def update_tracks(self, frame, raw_detections): """Run multi-target tracker on a particular sequence. Parameters ---------- frame : ndarray Path to the MOTChallenge sequence directory. raw_detections : list List of triples ( [left,top,w,h] , confidence, detection_class) Returns ------- list of track objects (Look into track.py for more info or see "main" section below in this script to see simple example) """ results = [] # raw_detections = [ d for d in raw_detections if d[0][2] > 0 and d[0][3] > 0] embeds = self.generate_embeds(frame, raw_detections) # Proper deep sort detection objects that consist of bbox, confidence and embedding. detections = self.create_detections(frame, raw_detections, embeds) # Run non-maxima suppression. boxes = np.array([d.tlwh for d in detections]) scores = np.array([d.confidence for d in detections]) indices = preprocessing.non_max_suppression( boxes, self.nms_max_overlap, scores) detections = [detections[i] for i in indices] # Update tracker. self.tracker.predict() self.tracker.update(detections) return self.tracker.tracks def generate_embeds(self, frame, raw_dets): crops = [] im_height, im_width = frame.shape[:2] for detection in raw_dets: if detection is None: continue # l,t,w,h = [int(x) for x in detection[0]] # r = l + w # b = t + h t,l,b,r,w,h = [int(detection[x]) for x in 'tlbrwh'] crop_l = max(0, l) crop_r = min(im_width, r) crop_t = max(0, t) crop_b = min(im_height, b) crops.append(frame[ crop_t:crop_b, crop_l:crop_r ]) return self.embedder.predict(crops) def create_detections(self, frame, raw_dets, embeds): detection_list = [] for i in range(len(embeds)): # detection_list.append(Detection(raw_dets[i][0], raw_dets[i][1], embeds[i])) detection = raw_dets[i] bbox = [detection[x] for x in 'ltwh'] confidence = detection['confidence'] detection_list.append(Detection(bbox, confidence, embeds[i])) return detection_list def refresh_track_ids(self): self.tracker._next_id
class DeepSort(object): def __init__(self, max_age = 30, nms_max_overlap=1.0, max_cosine_distance=0.2, nn_budget=None, override_track_class=None, clock=None, embedder=True, half=True, bgr=True, logger=None, polygon=False): ''' Parameters ---------- max_age : Optional[int] = 30 Maximum number of missed misses before a track is deleted. nms_max_overlap : Optional[float] = 1.0 Non-maxima suppression threshold: Maximum detection overlap, if is 1.0, nms will be disabled max_cosine_distance : Optional[float] = 0.2 Gating threshold for cosine distance nn_budget : Optional[int] = None Maximum size of the appearance descriptors, if None, no budget is enforced override_track_class : Optional[object] = None Giving this will override default Track class, this must inherit Track clock : Optional[object] = None Clock custom object provides date for track naming and facilitates track id reset every day, preventing overflow and overly large track ids. For example clock class, please see `utils/clock.py` embedder : Optional[bool] = True Whether to use in-built embedder or not. If False, then embeddings must be given during update half : Optional[bool] = True Whether to use half precision for deep embedder bgr : Optional[bool] = True Whether frame given to embedder is expected to be BGR or not (RGB) logger : Optional[object] = None logger object polygon: Optional[bool] = False Whether detections are polygons (e.g. oriented bounding boxes) ''' if logger is None: self.logger = default_logger else: self.logger = logger # self.video_info = video_info # assert clock is not None self.nms_max_overlap = nms_max_overlap metric = nn_matching.NearestNeighborDistanceMetric( "cosine", max_cosine_distance, nn_budget) self.tracker = Tracker(metric, max_age = max_age, override_track_class=override_track_class, clock=clock, logger=self.logger) if embedder: self.embedder = Embedder(half=half, max_batch_size=16, bgr=bgr) else: self.embedder = None self.polygon = polygon self.logger.info('DeepSort Tracker initialised') self.logger.info(f'- max age: {max_age}') self.logger.info(f'- appearance threshold: {max_cosine_distance}') self.logger.info(f'- nms threshold: {"OFF" if self.nms_max_overlap==1.0 else self.nms_max_overlap }') self.logger.info(f'- max num of appearance features: {nn_budget}') self.logger.info(f'- overriding track class : {"No" if override_track_class is None else "Yes"}' ) self.logger.info(f'- clock : {"No" if clock is None else "Yes"}' ) self.logger.info(f'- in-build embedder : {"No" if self.embedder is None else "Yes"}' ) self.logger.info(f'- polygon detections : {"No" if polygon is False else "Yes"}' ) def update_tracks(self, raw_detections, embeds=None, frame=None): """Run multi-target tracker on a particular sequence. Parameters ---------- raw_detections (horizontal bb) : List[ Tuple[ List[float or int], float, str ] ] List of detections, each in tuples of ( [left,top,w,h] , confidence, detection_class) raw_detections (polygon) : List[ List[float], List[int or str], List[float] ] List of Polygons, Classes, Confidences. All 3 sublists of the same length. A polygon defined as a ndarray-like [x1,y1,x2,y2,...]. embeds : Optional[ List[] ] = None List of appearance features corresponding to detections frame : Optional [ np.ndarray ] = None if embeds not given, Image frame must be given here, in [H,W,C]. Returns ------- list of track objects (Look into track.py for more info or see "main" section below in this script to see simple example) """ if embeds is None: if self.embedder is None: raise Exception('Embedder not created during init so embeddings must be given now!') if frame is None: raise Exception('either embeddings or frame must be given!') if not self.polygon: raw_detections = [ d for d in raw_detections if d[0][2] > 0 and d[0][3] > 0] if embeds is None: embeds = self.generate_embeds(frame, raw_detections) # Proper deep sort detection objects that consist of bbox, confidence and embedding. detections = self.create_detections(raw_detections, embeds) else: polygons, bounding_rects = self.process_polygons(raw_detections[0]) if embeds is None: embeds = self.generate_embeds_poly(frame, polygons, bounding_rects) # Proper deep sort detection objects that consist of bbox, confidence and embedding. detections = self.create_detections_poly(raw_detections, embeds, bounding_rects) # Run non-maxima suppression. boxes = np.array([d.ltwh for d in detections]) scores = np.array([d.confidence for d in detections]) if self.nms_max_overlap < 1.0: # nms_tic = time.perf_counter() indices = non_max_suppression( boxes, self.nms_max_overlap, scores) # nms_toc = time.perf_counter() # logger.debug(f'nms time: {nms_toc-nms_tic}s') detections = [detections[i] for i in indices] # Update tracker. self.tracker.predict() self.tracker.update(detections) return self.tracker.tracks def refresh_track_ids(self): self.tracker._next_id def generate_embeds(self, frame, raw_dets): crops = self.crop_bb(frame, raw_dets) return self.embedder.predict(crops) def generate_embeds_poly(self, frame, polygons, bounding_rects): crops = self.crop_poly_pad_black(frame, polygons, bounding_rects) return self.embedder.predict(crops) def create_detections(self, raw_dets, embeds): detection_list = [] for raw_det, embed in zip(raw_dets,embeds): detection_list.append(Detection(raw_det[0], raw_det[1], embed, class_name=raw_det[2])) #raw_det = [bbox, conf_score, class] return detection_list def create_detections_poly(self, dets, embeds, bounding_rects): detection_list = [] dets.extend([embeds, bounding_rects]) for raw_polygon, cl, score, embed, bounding_rect in zip(*dets): x,y,w,h = bounding_rect x = max(0, x) y = max(0, y) bbox = [x,y,w,h] detection_list.append(Detection(bbox, score, embed, class_name=cl, others=raw_polygon)) return detection_list @staticmethod def process_polygons(raw_polygons): polygons = [ [ polygon[x:x+2] for x in range(0, len(polygon), 2) ]for polygon in raw_polygons ] bounding_rects = [ cv2.boundingRect(np.array([polygon]).astype(int)) for polygon in polygons ] return polygons, bounding_rects @staticmethod def crop_bb(frame, raw_dets): crops = [] im_height, im_width = frame.shape[:2] for detection in raw_dets: l,t,w,h = [int(x) for x in detection[0]] r = l + w b = t + h crop_l = max(0, l) crop_r = min(im_width, r) crop_t = max(0, t) crop_b = min(im_height, b) crops.append(frame[crop_t:crop_b, crop_l:crop_r]) return crops @staticmethod def crop_poly_pad_black(frame, polygons, bounding_rects): masked_polys = [] im_height, im_width = frame.shape[:2] for polygon, bounding_rect in zip(polygons, bounding_rects): mask = np.zeros(frame.shape, dtype=np.uint8) polygon_mask = np.array([polygon]).astype(int) cv2.fillPoly(mask, polygon_mask, color=(255,255,255)) # apply the mask masked_image = cv2.bitwise_and(frame, mask) # crop masked image x,y,w,h = bounding_rect crop_l = max(0, x) crop_r = min(im_width, x+w) crop_t = max(0, y) crop_b = min(im_height, y+h) cropped = masked_image[crop_t:crop_b, crop_l:crop_r].copy() masked_polys.append(np.array(cropped)) return masked_polys
class DeepSort(object): def __init__(self, max_age=10, nms_max_overlap=1.0, max_cosine_distance=0.2, nn_budget=None, override_track_class=None): #, clock=None): ''' Input Params: - nms_max_overlap: Non-maxima suppression threshold: Maximum detection overlap - max_cosine_distance: Gating threshold for cosine distance - nn_budget: Maximum size of the appearance descriptors, if None, no budget is enforced ''' print('Initialising DeepSort..') # self.video_info = video_info #assert clock is not None self.nms_max_overlap = nms_max_overlap metric = nn_matching.NearestNeighborDistanceMetric( "cosine", max_cosine_distance, nn_budget) self.tracker = Tracker( metric, max_age=max_age, override_track_class=override_track_class) #, clock=clock) self.embedder = Embedder() print('DeepSort Tracker initialised!') def update_tracks(self, frame, raw_detections): """Run multi-target tracker on a particular sequence. Parameters ---------- frame : ndarray Path to the MOTChallenge sequence directory. raw_detections : list List of triples ( [left,top,w,h] , confidence, detection_class) Returns ------- list of track objects (Look into track.py for more info or see "main" section below in this script to see simple example) """ results = [] embeds = self.generate_embeds(frame, raw_detections) # Proper deep sort detection objects that consist of bbox, confidence and embedding. detections = self.create_detections(frame, raw_detections, embeds) #print(detections) # Run non-maxima suppression. boxes = np.array([d.tlwh for d in detections]) scores = np.array([d.confidence for d in detections]) indices = preprocessing.non_max_suppression(boxes, self.nms_max_overlap, scores) detections = [detections[i] for i in indices] # Update tracker. self.tracker.predict() self.tracker.update(detections) print(raw_detections) return self.tracker.tracks, raw_detections def generate_embeds(self, frame, raw_dets): crops = [] for detection in raw_dets: if detection is None: continue l, t, w, h = [int(x) for x in detection["bbox"]] crops.append(frame[t:t + h - 1, l:l + w - 1]) return self.embedder.predict(crops) def create_detections(self, frame, raw_dets, embeds): detection_list = [] # print(len(raw_dets)) # print(len(embeds)) for i in range(len(raw_dets)): # initially embeds detection_list.append( Detection(raw_dets[i]['bbox'], raw_dets[i]['score'], embeds[i])) return detection_list def refresh_track_ids(self): self.tracker._next_id # if __name__ == '__main__': # tracker = DeepSort(max_age = 30, nn_budget=100) # impath = '/home/levan/Pictures/auba.jpg' # print() # print('FRAME1') # frame1 = cv2.imread(impath) # detections1 = [ ( [0,0,50,50], 0.5 ), ([50,50, 50, 50], 0.5) ] # tracks = tracker.update_tracks(frame1, detections1) # for track in tracks: # print(track.track_id) # print(track.to_tlwh()) # print() # print('FRAME2') # # assume new frame # frame2 = frame1 # detections2 = [ ( [10,10,60,60], 0.8 ), ([60,50, 50, 50], 0.7) ] # tracks = tracker.update_tracks(frame2, detections2) # for track in tracks: # print(track.track_id) # print(track.to_tlwh())