_, img = vc.read() if img is None: break img = cv2.resize(img, (int(img.shape[1]*scale_factor), int(img.shape[0]*scale_factor))) # detect ball in frame (just one for now) bboxes = detector.detect(img) bb = None if bboxes is not None and len(bboxes)>0: for bb in bboxes: cv2.rectangle(img, (bb[0], bb[1]), (bb[2], bb[3]), (0, 255, 0), 2) pass # assume only 1 object bb = bboxes[0] # update kalman measurement pred_bb = kf.get_predicted_bb() if bb is not None: # if we have a measurement, correct using measurement corr_bb = kf.correct(bb) num_missed_det = 0 else: # if no measurement found, use prediction as measurement to correct if num_missed_det < max_num_missed_det: corr_bb = kf.correct(pred_bb) num_missed_det += 1 # count as missed detection else: corr_bb = None # add bbox to track if num_missed_det < max_num_missed_det: tracked_bbox.append(corr_bb) else:
class Track(object): def __init__(self): # each history entry is numpy array [frame_id, bbox_x1, bbox_y1, bbox_x2, bbox_y2, fvec_1...128] self.history = np.array([]) self.num_misses = 0 # num of missed assignments self.max_misses = const.MAX_NUM_MISSES_TRACK self.has_match = False self.delete_me = False # set for manual deletion self.kalman = KalmanFilter() color = tuple(np.random.random_integers(0, 255, size=3)) self.drawing_color = color self.predicted_next_bb = None self.LENGTH_ESTABLISHED = 1 # number of sequential detections before we consider it a track self.uid = uuid.uuid4() def get_length(self): return self.history.shape[0] def is_singular(self): return True if self.history.shape[ 0] == self.LENGTH_ESTABLISHED else False def is_established(self): return True if self.history.shape[ 0] > self.LENGTH_ESTABLISHED else False def is_empty(self): return True if self.history.shape[0] == 0 else False def is_dead(self): return True if (self.num_misses >= self.max_misses or self.delete_me is True) else False def propagate_track(self, frame_id): # propagate track as if there was a detection, perhaps object is temporarily occluded or not detected # use predicted bb as measurement det = Detection.det_from_numpy_array( self.history[self.history.shape[0] - 1]) det.bbox = self.get_predicted_next_bb() # TODO: adjust bbox to have same width height but only propegate x,y centroid position # pred_c_x, pred_c_y = util.centroid_from_bb(self.get_predicted_next_bb()) # wid, ht = util.wid_ht_from_bb(det.bbox) # det.bbox = np.array([pred_c_x - wid / 2, # pred_c_y - ht / 2, # pred_c_x + wid / 2, # pred_c_y + ht / 2], dtype=np.int32) det.frame_id = frame_id self.add_to_track(det) def get_predicted_next_bb(self): # # get a prediction using the latest history as a measurement # measurement = np.array([self.get_latest_bb()], dtype=np.float32).T return self.kalman.get_predicted_bb() def add_to_track(self, det): # use detection measurement to predict and correct the kalman filter corrected_bb = self.kalman.correct(det.bbox) # use corrected bbox det.bbox = corrected_bb # increment detections number of matches (could be assigned to several tracks, need to keep track of this) det.num_matches += 1 new_history = det.as_numpy_array() # print new_history if self.history.size > 0: self.history = np.vstack((self.history, new_history)) else: self.history = new_history def get_latest_fvec(self): # get feature vector from the latest detection in the track (already computed during detection phase) return self.history[self.history.shape[0] - 1][5:] def get_latest_bb(self): return self.history[self.history.shape[0] - 1][1:5] def draw_history(self, img, draw_at_bottom=False): if self.history.shape[0] > 1: bb_latest = self.get_latest_bb() cv2.rectangle(img, (int(bb_latest[0]), int(bb_latest[1])), (int(bb_latest[2]), int(bb_latest[3])), self.drawing_color, 2) # iterate through detection history prev_bb = self.history[0][1:5] for det in self.history: bb = det[1:5] # cv2.rectangle(img, tuple(bb[:2]),tuple(bb[2:]),(255,0,0),2) centroid = (int(bb[0] + (bb[2] - bb[0]) / 2), int(bb[1] + (bb[3] - bb[1]) / 2)) bottom = (int(bb[0] + (bb[2] - bb[0]) / 2), int(bb[3])) bottom_prev = (int(prev_bb[0] + (prev_bb[2] - prev_bb[0]) / 2), int(prev_bb[3])) # cv2.circle(img, centroid, 5, self.drawing_color, 2) # cv2.circle(img, bottom, 3, self.drawing_color, 2) cv2.line(img, bottom_prev, bottom, self.drawing_color, 4) prev_bb = bb