class Tracks(object): def __init__(self, detection, trackID): super(Tracks, self).__init__() self.KF = KalmanFilter() self.KF.predict() self.KF.correct(np.matrix(detection).reshape(3, 1)) self.trace = deque() self.prediction = detection.reshape(1,3) self.trackID = trackID self.skipped = 0 def predict(self, detection): self.prediction = np.array(self.KF.predict()).reshape(1,3) self.KF.correct(np.matrix(detection).reshape(3,1)) def predictNoDetect(self): self.prediction = np.array(self.KF.predict()).reshape(1,3) self.KF.update() def CheckMeasurement(self, cost): return self.KF.measurementProbability(cost)
class Instance(object): def __init__(self, config, video_helper): # fps: frame per second self.num_misses = 0 self.max_misses = config.MAX_NUM_MISSING_PERMISSION self.has_match = False # flags: self.delete....... self.kalman = KalmanFilter(video_helper) # self.history def add_to_track(self, tag, bbox): corrected_bbox = self.kalman.correct(bbox) # self.history.append(corrected_bbox) def get_predicted_bbox(self): # get a prediction return self.kalman.get_predicted_bbx()
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: tracked_bbox = [] # if too many missed detections, kill track # draw track history if len(tracked_bbox) > 0:
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
class Instance(object): def __init__(self, config, video_helper, frame): #each history entry is an array with [frame_id, tag, bbx_left, bbx_right, bbx_up, bbx_down] self.history = [] self.history_size = config.HISTORY_SIZE = 10 self.face_id = 'None' # 人脸识别 self.his_face_id = 'None' # 记录上一次预测的人脸ID self.emotion = 'None' # 表情识别 self.his_emotion = 'None' # 记录上一次表情 self.detector = config.detector self.num_misses = 0 # num of missed assignments self.max_misses = config.MAX_NUM_MISSING_PERMISSION self.has_match = False self.delete_duplicate = False self.delete_still = False self.delete_singular = False self.num_of_still = 0 # num of detector num self.kcf = KcfFilter(video_helper, frame) # video_helper here can provide us the fps self.kalman = KalmanFilter(video_helper) # this color is for bbx (color assigned to this instance itself) color = np.random.randint(0, 255, (1, 3))[0] self.color = [int(color[0]), int(color[1]), int(color[2])] # color needs to be a tuple # this color is for central point # because we need to fade the color self.center_color = [] self.center_color.append([int(color[0]), int(color[1]), int(color[2])]) self.predicted_next_bbx = None self.num_established = 1 # num of sequential detections before we consider it a track self.COLOR_FADING_PARAM = config.COLOR_FADING_PARAM # we still need to change it later self.speed = 0 self.direction = 0 # degree of velocity direction with [1, 0] self.still_history = 0 # def add_to_track(self, det): def add_to_track(self, tag, bbx, frame): # Same function with correct_track # Just make it more clear when it is the case that this particular detection is a new one and need to be # tracked later. # since here we are assured that this instance is detected, so it's not missed # self.num_misses = 0 # use measured data to correct the filter # still a list [x_left, x_right, y_up, y_bottom] if self.detector == "kcf": corrected_bbx = self.kcf.correct(bbx, frame) else: corrected_bbx = self.kalman.correct(bbx) # history: [tag, bbx_left, bbx_right, bbx_up, bbx_down, [color_b, color_g, color_r]] new_history = [ tag, corrected_bbx[0], corrected_bbx[1], corrected_bbx[2], corrected_bbx[3], [self.color[0], self.color[1], self.color[2]] ] if (len(self.history) == 0): self.history.append(new_history) else: for i in range(len(self.history)): for c in range(3): temp = self.history[i][5][c] self.history[i][5][c] = int( ((self.COLOR_FADING_PARAM - 1) / self.COLOR_FADING_PARAM) * temp) if self.history[i][5][c] < 0: self.history[i][5][c] = 0 self.history.insert(0, new_history) # we need to cut if we set if len(self.history) == self.COLOR_FADING_PARAM - 1: del self.history[-1] self.num_of_still += 1 def add_to_track_with_no_correction(self, tag, bbx, frame): new_history = [ tag, bbx[0], bbx[1], bbx[2], bbx[3], [self.color[0], self.color[1], self.color[2]] ] for i in range(len(self.history)): for c in range(3): temp = self.history[i][5][c] self.history[i][5][c] = int( ((self.COLOR_FADING_PARAM - 1) / self.COLOR_FADING_PARAM) * temp) if self.history[i][5][c] < 0: self.history[i][5][c] = 0 self.history.insert(0, new_history) # we need to cut if we set if len(self.history) == self.COLOR_FADING_PARAM - 1: del self.history[-1] def correct_track(self, det, frame): # Same function with add_to_track. # Just make it more clear when it is the case that we have a track and we need to correct that after we # have the measurement. # det: {'tag' : [bbx_left, bbx_right, bbx_up, bbx_bottom]} tag = list(det.keys())[0] bbx = det[tag] self.add_to_track(tag, bbx, frame) def get_predicted_bbx(self, frame): # get a prediction if self.detector == "kcf": return self.kcf.get_predicted_bbx(frame) elif self.detector == "kalman": return self.kalman.get_predicted_bbox() def get_latest_bbx(self): if len(self.history) == 0: return [] res = self.history[0] last_bbx = [res[1], res[2], res[3], res[4]] return last_bbx def get_ith_bbx(self, i): # if input i is int type if isinstance(i, int): if (i > 0 and i < len(self.history)) or (i < 0 and -i <= len(self.history)): res = self.history[i] ith_bbx = [res[1], res[2], res[3], res[4]] return ith_bbx # if input i is other type else: print("Wrong type!") return [] def get_first_bbx(self): return self.get_ith_bbx(-1) def get_latest_record(self): if len(self.history) == 0: return [] return self.history[0] def get_age(self): return len(self.history)