def evaluation(result_rect_list, gt_list): print("Merging method.") matching_lists, correct_results, overlap_json, non_overlap_json = \ find_result_ground_truth_correspondence(gt_list, result_rect_list) print("Number of detected bounding boxes: %d" % len(result_rect_list)) print("Number of correct bounding boxes: %d" % len(correct_results)) # Calculate precision and recall for the words. total_delete = total_editing = 0 gt_count = result_count = 0 visited_gt = [] temp = 0 for i in range(0, len(gt_list), 1): gt_rect_list = gt_list[i]['rects'] for j in range(0, len(gt_rect_list), 1): temp += 1 # Find all the matching ground truths and results. if (i, j) in visited_gt: continue ret = MatchingHelper.find_matching(gt_list, matching_lists, (i, j)) # Determine the merging order of ground truths. ground_truths = ret[0] for k in range(0, len(ground_truths)): gt = ground_truths[k] ground_truths[k] = (gt[0], gt[1], gt_list[i]['rects'][0].get_center()) visited_gt.append((gt[0], gt[1])) if k == 0: orientation = gt_list[i]['orientation'] ground_truths = sorted(ground_truths, key=MatchingHelper.ground_truth_key) if len(ground_truths) > 1: ground_truths, orientation = MatchingHelper.merge_ground_truth(ground_truths, gt_list) # Determine the merging order of results. results = ret[1] if len(results) > 1: results = MatchingHelper.merge_result(results, result_rect_list, orientation) # Merge the result string and the ground truth string. gt_str = "" for gt in ground_truths: gt_str = gt_str + gt_list[gt[0]]['rects'][gt[1]].text # gt_str = gt_str[:-1] result_str = "" for r in results: result_str = result_str + result_rect_list[r].text # print("%d to %d." % (len(ground_truths), len(results))) # print("Ground truth string: %s" % gt_str) # print("Result string: %s" % result_str) # Calculate the precision and recall. ret, gt_mlist, result_mlist = WordEvaluation.levenshtein_distance(gt_str, result_str) # m_str = "" # for e in gt_mlist: # if not e: # m_str += "F" # else: # m_str += "T" # print("matching: %s" % m_str) # print("add: %d, delete: %d, editing: %d" % (ret[1], ret[2], ret[3])) total_delete += ret[2] total_editing += ret[3] gt_count += len(gt_str) result_count += len(result_str) total_result_count = 0 for r in result_rect_list: total_result_count += len(r.textFound) # print("Visited GT number: %d and %d" % (len(visited_gt), temp)) print("Number of ground truth characters: %d" % gt_count) print("Number of detected characters: %d" % total_result_count) cost = total_editing + total_delete precision = float(total_result_count - (total_result_count - result_count + cost)) / total_result_count recall = float(result_count - cost) / gt_count print("Text Recognition Precision: %f" % precision) print("Text Recognition Recall: %f" % recall) return overlap_json, non_overlap_json
def evaluation_simple(result_rect_list, gt_list, area_threshold=0.7, group_para=0): # The json file records the overlap areas. overlap_json = GeoJsonWriter.init_output_json_structure() # The json file records the rectangles which we don't consider them as correct ones. non_overlap_json = GeoJsonWriter.init_output_json_structure() correct_results = set() # Find the correct and incorrect bounding boxes. for k in range(0, len(result_rect_list)): rect = result_rect_list[k] result_area = rect.get_area() gt_list_backup = copy.copy(gt_list) result_rect_list_backup = copy.copy(result_rect_list) is_invalid = False for i in range(0, len(gt_list), 1): gt_rect_list = gt_list[i]['rects'] for j in range(0, len(gt_rect_list)): gt_rect = gt_rect_list[j] gt_area = gt_rect.get_area() overlap_polygon = rect.get_overlap_polygon(gt_rect) if overlap_polygon is None: pass else: overlap_area = overlap_polygon.get_area() overlap_valid = False if overlap_area >= area_threshold * gt_area or overlap_area >= area_threshold * result_area: if result_area > 5 * gt_area: is_invalid = False break # pass overlap_valid = True rect.positive = True gt_list[i]['found'][j] = True correct_results.add(rect) gt_list[i]['rects'][j].text = gt_list[i]['rects'][j].text.replace(".", "") result_rect_list[k].text = result_rect_list[k].text.replace(".", "") ret, gt_mlist, result_mlist = WordEvaluation.levenshtein_distance(gt_list[i]['rects'][j].text, result_rect_list[k].text) for m in range(0, len(gt_mlist)): gt_list[i]['rects'][j].textFound[m] = gt_list[i]['rects'][j].textFound[m] or gt_mlist[m] for r in range(0, len(result_mlist)): rect.textFound[r] = rect.textFound[r] or result_mlist[r] rect.textGroup[r].append(int(gt_list[i]['rects'][j].groupId)) new_feature = GeoJsonWriter.generate_overlap_feature(overlap_polygon, overlap_valid, tag=i) overlap_json['features'].append(new_feature) rect.groundTruth.append(gt_rect.text) if is_invalid: print('Invalid roll back.') gt_list = gt_list_backup result_rect_list = result_rect_list_backup break # Compute the precision and recall precision_list = [] recall_list = [] total_extracted_characters_list = [] total_gt_characters_list = [] total_gt_characters = total_extracted_characters = 0 correct_result_characters = correct_gt_characters = 0 for r in result_rect_list: # print(r.text) for i in range(0, len(r.text)): if group_para in r.textGroup[i] or group_para == 0: if r.textFound[i]: # print(r.text[i]) correct_result_characters += 1 total_extracted_characters += 1 elif len(r.textGroup[i]) == 0: total_extracted_characters += 1 # print("\nGround truth") for i in range(0, len(gt_list), 1): gt_rect_list = gt_list[i]['rects'] for j in range(0, len(gt_rect_list), 1): if group_para == int(gt_list[i]['rects'][j].groupId) or group_para == 0: gt_rect = gt_rect_list[j] # print(gt_rect.text) for k in gt_rect.textFound: if k: correct_gt_characters += 1 total_gt_characters += 1 recall = 0 if total_gt_characters == 0 else (float(correct_gt_characters) / total_gt_characters) precision = 0 if total_extracted_characters == 0 else (float(correct_result_characters) / total_extracted_characters) print("Detected Bounding Boxes: %d" % len(result_rect_list)) print("Correct Bounding Boxes: %d" % len(correct_results)) print("Number of ground truth characters: %d" % total_gt_characters) print("Number of detected characters: %d" % total_extracted_characters) print("Number of correct detetected char: %d" % correct_result_characters) print("Text Recognition Precision: %f" % precision) print("Text Recognition Recall: %f" % recall) precision_list.append(precision) recall_list.append(recall) total_extracted_characters_list.append(total_extracted_characters) total_gt_characters_list.append(total_gt_characters) return overlap_json, non_overlap_json, precision_list, recall_list, total_extracted_characters_list, total_gt_characters_list
if overlap_polygon is None: pass else: overlap_area = overlap_polygon.get_area() overlap_valid = False if overlap_area >= area_threshold * gt_area or overlap_area >= area_threshold * result_area: overlap_valid = True rect.positive = True gt_list[u]['found'][j] = True rect.groundTruth.append(gt_rect.text) gt_list[u]['rects'][j].text = gt_list[u]['rects'][j].text.replace(".", "") rect.text = rect.text.replace(".", "") ret, gt_mlist, result_mlist = WordEvaluation.levenshtein_distance(gt_list[u]['rects'][j].text, rect.text) for m in range(0, len(gt_mlist)): gt_list[u]['rects'][j].textFound[m] = gt_list[u]['rects'][j].textFound[m] or gt_mlist[m] for r in range(0, len(result_mlist)): rect.textFound[r] = rect.textFound[r] or result_mlist[r] rect.textGroup[r].append(int(gt_list[u]['rects'][j].groupId)) # sys.exit(0) # Begin to evaluate the candidates. lines = cf.readlines() count = 0 candidates = [] word_score = {}