Spaces:
Runtime error
Runtime error
# Copyright (c) OpenMMLab. All rights reserved. | |
import numpy as np | |
import mmocr.utils as utils | |
from . import utils as eval_utils | |
def compute_recall_precision(gt_polys, pred_polys): | |
"""Compute the recall and the precision matrices between gt and predicted | |
polygons. | |
Args: | |
gt_polys (list[Polygon]): List of gt polygons. | |
pred_polys (list[Polygon]): List of predicted polygons. | |
Returns: | |
recall (ndarray): Recall matrix of size gt_num x det_num. | |
precision (ndarray): Precision matrix of size gt_num x det_num. | |
""" | |
assert isinstance(gt_polys, list) | |
assert isinstance(pred_polys, list) | |
gt_num = len(gt_polys) | |
det_num = len(pred_polys) | |
sz = [gt_num, det_num] | |
recall = np.zeros(sz) | |
precision = np.zeros(sz) | |
# compute area recall and precision for each (gt, det) pair | |
# in one img | |
for gt_id in range(gt_num): | |
for pred_id in range(det_num): | |
gt = gt_polys[gt_id] | |
det = pred_polys[pred_id] | |
inter_area = eval_utils.poly_intersection(det, gt) | |
gt_area = gt.area | |
det_area = det.area | |
if gt_area != 0: | |
recall[gt_id, pred_id] = inter_area / gt_area | |
if det_area != 0: | |
precision[gt_id, pred_id] = inter_area / det_area | |
return recall, precision | |
def eval_hmean_ic13(det_boxes, | |
gt_boxes, | |
gt_ignored_boxes, | |
precision_thr=0.4, | |
recall_thr=0.8, | |
center_dist_thr=1.0, | |
one2one_score=1., | |
one2many_score=0.8, | |
many2one_score=1.): | |
"""Evaluate hmean of text detection using the icdar2013 standard. | |
Args: | |
det_boxes (list[list[list[float]]]): List of arrays of shape (n, 2k). | |
Each element is the det_boxes for one img. k>=4. | |
gt_boxes (list[list[list[float]]]): List of arrays of shape (m, 2k). | |
Each element is the gt_boxes for one img. k>=4. | |
gt_ignored_boxes (list[list[list[float]]]): List of arrays of | |
(l, 2k). Each element is the ignored gt_boxes for one img. k>=4. | |
precision_thr (float): Precision threshold of the iou of one | |
(gt_box, det_box) pair. | |
recall_thr (float): Recall threshold of the iou of one | |
(gt_box, det_box) pair. | |
center_dist_thr (float): Distance threshold of one (gt_box, det_box) | |
center point pair. | |
one2one_score (float): Reward when one gt matches one det_box. | |
one2many_score (float): Reward when one gt matches many det_boxes. | |
many2one_score (float): Reward when many gts match one det_box. | |
Returns: | |
hmean (tuple[dict]): Tuple of dicts which encodes the hmean for | |
the dataset and all images. | |
""" | |
assert utils.is_3dlist(det_boxes) | |
assert utils.is_3dlist(gt_boxes) | |
assert utils.is_3dlist(gt_ignored_boxes) | |
assert 0 <= precision_thr <= 1 | |
assert 0 <= recall_thr <= 1 | |
assert center_dist_thr > 0 | |
assert 0 <= one2one_score <= 1 | |
assert 0 <= one2many_score <= 1 | |
assert 0 <= many2one_score <= 1 | |
img_num = len(det_boxes) | |
assert img_num == len(gt_boxes) | |
assert img_num == len(gt_ignored_boxes) | |
dataset_gt_num = 0 | |
dataset_pred_num = 0 | |
dataset_hit_recall = 0.0 | |
dataset_hit_prec = 0.0 | |
img_results = [] | |
for i in range(img_num): | |
gt = gt_boxes[i] | |
gt_ignored = gt_ignored_boxes[i] | |
pred = det_boxes[i] | |
gt_num = len(gt) | |
ignored_num = len(gt_ignored) | |
pred_num = len(pred) | |
accum_recall = 0. | |
accum_precision = 0. | |
gt_points = gt + gt_ignored | |
gt_polys = [eval_utils.points2polygon(p) for p in gt_points] | |
gt_ignored_index = [gt_num + i for i in range(len(gt_ignored))] | |
gt_num = len(gt_polys) | |
pred_polys, pred_points, pred_ignored_index = eval_utils.ignore_pred( | |
pred, gt_ignored_index, gt_polys, precision_thr) | |
if pred_num > 0 and gt_num > 0: | |
gt_hit = np.zeros(gt_num, np.int8).tolist() | |
pred_hit = np.zeros(pred_num, np.int8).tolist() | |
# compute area recall and precision for each (gt, pred) pair | |
# in one img. | |
recall_mat, precision_mat = compute_recall_precision( | |
gt_polys, pred_polys) | |
# match one gt to one pred box. | |
for gt_id in range(gt_num): | |
for pred_id in range(pred_num): | |
if (gt_hit[gt_id] != 0 or pred_hit[pred_id] != 0 | |
or gt_id in gt_ignored_index | |
or pred_id in pred_ignored_index): | |
continue | |
match = eval_utils.one2one_match_ic13( | |
gt_id, pred_id, recall_mat, precision_mat, recall_thr, | |
precision_thr) | |
if match: | |
gt_point = np.array(gt_points[gt_id]) | |
det_point = np.array(pred_points[pred_id]) | |
norm_dist = eval_utils.box_center_distance( | |
det_point, gt_point) | |
norm_dist /= eval_utils.box_diag( | |
det_point) + eval_utils.box_diag(gt_point) | |
norm_dist *= 2.0 | |
if norm_dist < center_dist_thr: | |
gt_hit[gt_id] = 1 | |
pred_hit[pred_id] = 1 | |
accum_recall += one2one_score | |
accum_precision += one2one_score | |
# match one gt to many det boxes. | |
for gt_id in range(gt_num): | |
if gt_id in gt_ignored_index: | |
continue | |
match, match_det_set = eval_utils.one2many_match_ic13( | |
gt_id, recall_mat, precision_mat, recall_thr, | |
precision_thr, gt_hit, pred_hit, pred_ignored_index) | |
if match: | |
gt_hit[gt_id] = 1 | |
accum_recall += one2many_score | |
accum_precision += one2many_score * len(match_det_set) | |
for pred_id in match_det_set: | |
pred_hit[pred_id] = 1 | |
# match many gt to one det box. One pair of (det,gt) are matched | |
# successfully if their recall, precision, normalized distance | |
# meet some thresholds. | |
for pred_id in range(pred_num): | |
if pred_id in pred_ignored_index: | |
continue | |
match, match_gt_set = eval_utils.many2one_match_ic13( | |
pred_id, recall_mat, precision_mat, recall_thr, | |
precision_thr, gt_hit, pred_hit, gt_ignored_index) | |
if match: | |
pred_hit[pred_id] = 1 | |
accum_recall += many2one_score * len(match_gt_set) | |
accum_precision += many2one_score | |
for gt_id in match_gt_set: | |
gt_hit[gt_id] = 1 | |
gt_care_number = gt_num - ignored_num | |
pred_care_number = pred_num - len(pred_ignored_index) | |
r, p, h = eval_utils.compute_hmean(accum_recall, accum_precision, | |
gt_care_number, pred_care_number) | |
img_results.append({'recall': r, 'precision': p, 'hmean': h}) | |
dataset_gt_num += gt_care_number | |
dataset_pred_num += pred_care_number | |
dataset_hit_recall += accum_recall | |
dataset_hit_prec += accum_precision | |
total_r, total_p, total_h = eval_utils.compute_hmean( | |
dataset_hit_recall, dataset_hit_prec, dataset_gt_num, dataset_pred_num) | |
dataset_results = { | |
'num_gts': dataset_gt_num, | |
'num_dets': dataset_pred_num, | |
'num_recall': dataset_hit_recall, | |
'num_precision': dataset_hit_prec, | |
'recall': total_r, | |
'precision': total_p, | |
'hmean': total_h | |
} | |
return dataset_results, img_results | |