def match_poses(cand_infos, group_keys=['scene_id', 'view_id', 'label']):
    assert ('error' in cand_infos)
    matches = []

    def match_label_preds(group):
        gt_ids_matched = set()
        group = group.reset_index(drop=True)
        gb_pred = group.groupby('pred_id', sort=False)
        ids_sorted = gb_pred.first().sort_values('score', ascending=False)
        gb_pred_groups = gb_pred.groups
        for (idx, _) in ids_sorted.iterrows():
            pred_group = group.iloc[gb_pred_groups[idx]]
            best_error = np.inf
            best_match = None
            for (_, tentative_match) in pred_group.iterrows():
                if ((tentative_match['error'] < best_error) and (tentative_match['gt_id'] not in gt_ids_matched)):
                    best_match = tentative_match
                    best_error = tentative_match['error']
            if (best_match is not None):
                gt_ids_matched.add(best_match['gt_id'])
                matches.append(best_match)
    if (len(cand_infos) > 0):
        cand_infos.groupby(group_keys).apply(match_label_preds)
        matches = pd.DataFrame(matches).reset_index(drop=True)
    else:
        matches = cand_infos
    return matches
def match_poses(cand_infos, group_keys=['scene_id', 'view_id', 'label']):
    assert ('error' in cand_infos)
    matches = []

    def match_label_preds(group):
        gt_ids_matched = set()
        group = group.reset_index(drop=True)
        gb_pred = group.groupby('pred_id', sort=False)
        ids_sorted = gb_pred.first().sort_values('score', ascending=False)
        gb_pred_groups = gb_pred.groups
        for (idx, _) in ids_sorted.iterrows():
            pred_group = group.iloc[gb_pred_groups[idx]]
            best_error = np.inf
            best_match = None
            for (_, tentative_match) in pred_group.iterrows():
                if ((tentative_match['error'] < best_error) and (tentative_match['gt_id'] not in gt_ids_matched)):
                    best_match = tentative_match
                    best_error = tentative_match['error']
            if (best_match is not None):
                gt_ids_matched.add(best_match['gt_id'])
                matches.append(best_match)
    if (len(cand_infos) > 0):
        cand_infos.groupby(group_keys).apply(match_label_preds)
        matches = pd.DataFrame(matches).reset_index(drop=True)
    else:
        matches = cand_infos
    return matches