def average_recall_vs_avg_nr_proposals(ground_truth, proposals, max_avg_nr_proposals=None, tiou_thresholds=np.linspace(0.5, 0.95, 10)): """ Computes the average recall given an average number of proposals per video. Parameters ---------- ground_truth : df Data frame containing the ground truth instances. Required fields: ['video-id', 't-start', 't-end'] proposal : df Data frame containing the proposal instances. Required fields: ['video-id, 't-start', 't-end', 'score'] tiou_thresholds : 1darray, optional array with tiou thresholds. Outputs ------- recall : 2darray recall[i,j] is recall at ith tiou threshold at the jth average number of average number of proposals per video. average_recall : 1darray recall averaged over a list of tiou threshold. This is equivalent to recall.mean(axis=0). proposals_per_video : 1darray average number of proposals per video. """ # Get list of videos. video_lst = ground_truth['video-id'].unique() if not max_avg_nr_proposals: max_avg_nr_proposals = float(proposals.shape[0])/video_lst.shape[0] ratio = max_avg_nr_proposals*float(video_lst.shape[0])/proposals.shape[0] # Adaptation to query faster ground_truth_gbvn = ground_truth.groupby('video-id') proposals_gbvn = proposals.groupby('video-id') # For each video, computes tiou scores among the retrieved proposals. score_lst = [] total_nr_proposals = 0 for videoid in video_lst: # Get ground-truth instances associated to this video. ground_truth_videoid = ground_truth_gbvn.get_group(videoid) this_video_ground_truth = ground_truth_videoid.loc[:,['t-start', 't-end']].values # Get proposals for this video. try: proposals_videoid = proposals_gbvn.get_group(videoid) except: n = this_video_ground_truth.shape[0] score_lst.append(np.zeros((n, 1))) continue this_video_proposals = proposals_videoid.loc[:, ['t-start', 't-end']].values if this_video_proposals.shape[0] == 0: n = this_video_ground_truth.shape[0] score_lst.append(np.zeros((n, 1))) continue # Sort proposals by score. sort_idx = proposals_videoid['score'].argsort()[::-1] this_video_proposals = this_video_proposals[sort_idx, :] if this_video_proposals.ndim != 2: this_video_proposals = np.expand_dims(this_video_proposals, axis=0) if this_video_ground_truth.ndim != 2: this_video_ground_truth = np.expand_dims(this_video_ground_truth, axis=0) nr_proposals = np.minimum(int(this_video_proposals.shape[0] * ratio), this_video_proposals.shape[0]) total_nr_proposals += nr_proposals this_video_proposals = this_video_proposals[:nr_proposals, :] # Compute tiou scores. tiou = wrapper_segment_iou(this_video_proposals, this_video_ground_truth) score_lst.append(tiou) # Given that the length of the videos is really varied, we # compute the number of proposals in terms of a ratio of the total # proposals retrieved, i.e. average recall at a percentage of proposals # retrieved per video. # Computes average recall. pcn_lst = np.arange(1, 101) / 100.0 *(max_avg_nr_proposals*float(video_lst.shape[0])/total_nr_proposals) matches = np.empty((video_lst.shape[0], pcn_lst.shape[0])) positives = np.empty(video_lst.shape[0]) recall = np.empty((tiou_thresholds.shape[0], pcn_lst.shape[0])) # Iterates over each tiou threshold. for ridx, tiou in enumerate(tiou_thresholds): # Inspect positives retrieved per video at different # number of proposals (percentage of the total retrieved). for i, score in enumerate(score_lst): # Total positives per video. positives[i] = score.shape[0] # Find proposals that satisfies minimum tiou threshold. true_positives_tiou = score >= tiou # Get number of proposals as a percentage of total retrieved. pcn_proposals = np.minimum((score.shape[1] * pcn_lst).astype(np.int), score.shape[1]) for j, nr_proposals in enumerate(pcn_proposals): # Compute the number of matches for each percentage of the proposals matches[i, j] = np.count_nonzero((true_positives_tiou[:, :nr_proposals]).sum(axis=1)) # Computes recall given the set of matches per video. recall[ridx, :] = matches.sum(axis=0) / positives.sum() # Recall is averaged. avg_recall = recall.mean(axis=0) # Get the average number of proposals per video. proposals_per_video = pcn_lst * (float(total_nr_proposals) / video_lst.shape[0]) return recall, avg_recall, proposals_per_video
def average_recall_vs_avg_nr_proposals(ground_truth, proposals, max_avg_nr_proposals=None, tiou_thresholds=np.linspace(0.5, 0.95, 10)): """ Computes the average recall given an average number of proposals per video. Parameters ---------- ground_truth : df Data frame containing the ground truth instances. Required fields: ['video-id', 't-start', 't-end'] proposal : df Data frame containing the proposal instances. Required fields: ['video-id, 't-start', 't-end', 'score'] tiou_thresholds : 1darray, optional array with tiou thresholds. Outputs ------- recall : 2darray recall[i,j] is recall at ith tiou threshold at the jth average number of average number of proposals per video. average_recall : 1darray recall averaged over a list of tiou threshold. This is equivalent to recall.mean(axis=0). proposals_per_video : 1darray average number of proposals per video. """ # Get list of videos. video_lst = ground_truth['video-id'].unique() if not max_avg_nr_proposals: max_avg_nr_proposals = float(proposals.shape[0])/video_lst.shape[0] ratio = max_avg_nr_proposals*float(video_lst.shape[0])/proposals.shape[0] # Adaptation to query faster ground_truth_gbvn = ground_truth.groupby('video-id') proposals_gbvn = proposals.groupby('video-id') # For each video, computes tiou scores among the retrieved proposals. score_lst = [] total_nr_proposals = 0 for videoid in video_lst: # Get ground-truth instances associated to this video. ground_truth_videoid = ground_truth_gbvn.get_group(videoid) this_video_ground_truth = ground_truth_videoid.loc[:,['t-start', 't-end']].values # Get proposals for this video. try: proposals_videoid = proposals_gbvn.get_group(videoid) except: n = this_video_ground_truth.shape[0] score_lst.append(np.zeros((n, 1))) continue this_video_proposals = proposals_videoid.loc[:, ['t-start', 't-end']].values if this_video_proposals.shape[0] == 0: n = this_video_ground_truth.shape[0] score_lst.append(np.zeros((n, 1))) continue # Sort proposals by score. sort_idx = proposals_videoid['score'].argsort()[::-1] this_video_proposals = this_video_proposals[sort_idx, :] if this_video_proposals.ndim != 2: this_video_proposals = np.expand_dims(this_video_proposals, axis=0) if this_video_ground_truth.ndim != 2: this_video_ground_truth = np.expand_dims(this_video_ground_truth, axis=0) nr_proposals = np.minimum(int(this_video_proposals.shape[0] * ratio), this_video_proposals.shape[0]) total_nr_proposals += nr_proposals this_video_proposals = this_video_proposals[:nr_proposals, :] # Compute tiou scores. tiou = wrapper_segment_iou(this_video_proposals, this_video_ground_truth) score_lst.append(tiou) # Given that the length of the videos is really varied, we # compute the number of proposals in terms of a ratio of the total # proposals retrieved, i.e. average recall at a percentage of proposals # retrieved per video. # Computes average recall. pcn_lst = np.arange(1, 101) / 100.0 *(max_avg_nr_proposals*float(video_lst.shape[0])/total_nr_proposals) matches = np.empty((video_lst.shape[0], pcn_lst.shape[0])) positives = np.empty(video_lst.shape[0]) recall = np.empty((tiou_thresholds.shape[0], pcn_lst.shape[0])) # Iterates over each tiou threshold. for ridx, tiou in enumerate(tiou_thresholds): # Inspect positives retrieved per video at different # number of proposals (percentage of the total retrieved). for i, score in enumerate(score_lst): # Total positives per video. positives[i] = score.shape[0] # Find proposals that satisfies minimum tiou threshold. true_positives_tiou = score >= tiou # Get number of proposals as a percentage of total retrieved. pcn_proposals = np.minimum((score.shape[1] * pcn_lst).astype(np.int), score.shape[1]) for j, nr_proposals in enumerate(pcn_proposals): # Compute the number of matches for each percentage of the proposals matches[i, j] = np.count_nonzero((true_positives_tiou[:, :nr_proposals]).sum(axis=1)) # Computes recall given the set of matches per video. recall[ridx, :] = matches.sum(axis=0) / positives.sum() # Recall is averaged. avg_recall = recall.mean(axis=0) # Get the average number of proposals per video. proposals_per_video = pcn_lst * (float(total_nr_proposals) / video_lst.shape[0]) return recall, avg_recall, proposals_per_video