magic_model_utils.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. """
  2. 包含两个MagicModel类中重复使用的方法和逻辑
  3. """
  4. from typing import List, Dict, Any, Callable
  5. from mineru.utils.boxbase import bbox_distance, is_in
  6. def reduct_overlap(bboxes: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
  7. """
  8. 去除重叠的bbox,保留不被其他bbox包含的bbox
  9. Args:
  10. bboxes: 包含bbox信息的字典列表
  11. Returns:
  12. 去重后的bbox列表
  13. """
  14. N = len(bboxes)
  15. keep = [True] * N
  16. for i in range(N):
  17. for j in range(N):
  18. if i == j:
  19. continue
  20. if is_in(bboxes[i]['bbox'], bboxes[j]['bbox']):
  21. keep[i] = False
  22. return [bboxes[i] for i in range(N) if keep[i]]
  23. def tie_up_category_by_distance_v3(
  24. get_subjects_func: Callable,
  25. get_objects_func: Callable,
  26. extract_subject_func: Callable = None,
  27. extract_object_func: Callable = None
  28. ):
  29. """
  30. 通用的类别关联方法,用于将主体对象与客体对象进行关联
  31. 参数:
  32. get_subjects_func: 函数,提取主体对象
  33. get_objects_func: 函数,提取客体对象
  34. extract_subject_func: 函数,自定义提取主体属性(默认使用bbox和其他属性)
  35. extract_object_func: 函数,自定义提取客体属性(默认使用bbox和其他属性)
  36. 返回:
  37. 关联后的对象列表
  38. """
  39. subjects = get_subjects_func()
  40. objects = get_objects_func()
  41. # 如果没有提供自定义提取函数,使用默认函数
  42. if extract_subject_func is None:
  43. extract_subject_func = lambda x: x
  44. if extract_object_func is None:
  45. extract_object_func = lambda x: x
  46. ret = []
  47. N, M = len(subjects), len(objects)
  48. subjects.sort(key=lambda x: x["bbox"][0] ** 2 + x["bbox"][1] ** 2)
  49. objects.sort(key=lambda x: x["bbox"][0] ** 2 + x["bbox"][1] ** 2)
  50. OBJ_IDX_OFFSET = 10000
  51. SUB_BIT_KIND, OBJ_BIT_KIND = 0, 1
  52. all_boxes_with_idx = [(i, SUB_BIT_KIND, sub["bbox"][0], sub["bbox"][1]) for i, sub in enumerate(subjects)] + [
  53. (i + OBJ_IDX_OFFSET, OBJ_BIT_KIND, obj["bbox"][0], obj["bbox"][1]) for i, obj in enumerate(objects)
  54. ]
  55. seen_idx = set()
  56. seen_sub_idx = set()
  57. while N > len(seen_sub_idx):
  58. candidates = []
  59. for idx, kind, x0, y0 in all_boxes_with_idx:
  60. if idx in seen_idx:
  61. continue
  62. candidates.append((idx, kind, x0, y0))
  63. if len(candidates) == 0:
  64. break
  65. left_x = min([v[2] for v in candidates])
  66. top_y = min([v[3] for v in candidates])
  67. candidates.sort(key=lambda x: (x[2] - left_x) ** 2 + (x[3] - top_y) ** 2)
  68. fst_idx, fst_kind, left_x, top_y = candidates[0]
  69. fst_bbox = subjects[fst_idx]['bbox'] if fst_kind == SUB_BIT_KIND else objects[fst_idx - OBJ_IDX_OFFSET]['bbox']
  70. candidates.sort(
  71. key=lambda x: bbox_distance(fst_bbox, subjects[x[0]]['bbox']) if x[1] == SUB_BIT_KIND else bbox_distance(
  72. fst_bbox, objects[x[0] - OBJ_IDX_OFFSET]['bbox']))
  73. nxt = None
  74. for i in range(1, len(candidates)):
  75. if candidates[i][1] ^ fst_kind == 1:
  76. nxt = candidates[i]
  77. break
  78. if nxt is None:
  79. break
  80. if fst_kind == SUB_BIT_KIND:
  81. sub_idx, obj_idx = fst_idx, nxt[0] - OBJ_IDX_OFFSET
  82. else:
  83. sub_idx, obj_idx = nxt[0], fst_idx - OBJ_IDX_OFFSET
  84. pair_dis = bbox_distance(subjects[sub_idx]["bbox"], objects[obj_idx]["bbox"])
  85. nearest_dis = float("inf")
  86. for i in range(N):
  87. # 取消原先算法中 1对1 匹配的偏置
  88. # if i in seen_idx or i == sub_idx:continue
  89. nearest_dis = min(nearest_dis, bbox_distance(subjects[i]["bbox"], objects[obj_idx]["bbox"]))
  90. if pair_dis >= 3 * nearest_dis:
  91. seen_idx.add(sub_idx)
  92. continue
  93. seen_idx.add(sub_idx)
  94. seen_idx.add(obj_idx + OBJ_IDX_OFFSET)
  95. seen_sub_idx.add(sub_idx)
  96. ret.append(
  97. {
  98. "sub_bbox": extract_subject_func(subjects[sub_idx]),
  99. "obj_bboxes": [extract_object_func(objects[obj_idx])],
  100. "sub_idx": sub_idx,
  101. }
  102. )
  103. for i in range(len(objects)):
  104. j = i + OBJ_IDX_OFFSET
  105. if j in seen_idx:
  106. continue
  107. seen_idx.add(j)
  108. nearest_dis, nearest_sub_idx = float("inf"), -1
  109. for k in range(len(subjects)):
  110. dis = bbox_distance(objects[i]["bbox"], subjects[k]["bbox"])
  111. if dis < nearest_dis:
  112. nearest_dis = dis
  113. nearest_sub_idx = k
  114. for k in range(len(subjects)):
  115. if k != nearest_sub_idx:
  116. continue
  117. if k in seen_sub_idx:
  118. for kk in range(len(ret)):
  119. if ret[kk]["sub_idx"] == k:
  120. ret[kk]["obj_bboxes"].append(extract_object_func(objects[i]))
  121. break
  122. else:
  123. ret.append(
  124. {
  125. "sub_bbox": extract_subject_func(subjects[k]),
  126. "obj_bboxes": [extract_object_func(objects[i])],
  127. "sub_idx": k,
  128. }
  129. )
  130. seen_sub_idx.add(k)
  131. seen_idx.add(k)
  132. for i in range(len(subjects)):
  133. if i in seen_sub_idx:
  134. continue
  135. ret.append(
  136. {
  137. "sub_bbox": extract_subject_func(subjects[i]),
  138. "obj_bboxes": [],
  139. "sub_idx": i,
  140. }
  141. )
  142. return ret