magic-pdf 0.7.1__py3-none-any.whl → 0.8.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. magic_pdf/dict2md/ocr_mkcontent.py +130 -76
  2. magic_pdf/integrations/__init__.py +0 -0
  3. magic_pdf/integrations/rag/__init__.py +0 -0
  4. magic_pdf/integrations/rag/api.py +82 -0
  5. magic_pdf/integrations/rag/type.py +82 -0
  6. magic_pdf/integrations/rag/utils.py +285 -0
  7. magic_pdf/layout/layout_sort.py +472 -283
  8. magic_pdf/libs/boxbase.py +188 -149
  9. magic_pdf/libs/draw_bbox.py +113 -87
  10. magic_pdf/libs/ocr_content_type.py +21 -18
  11. magic_pdf/libs/version.py +1 -1
  12. magic_pdf/model/doc_analyze_by_custom_model.py +14 -2
  13. magic_pdf/model/magic_model.py +283 -166
  14. magic_pdf/model/model_list.py +8 -0
  15. magic_pdf/model/pdf_extract_kit.py +105 -15
  16. magic_pdf/model/pek_sub_modules/self_modify.py +84 -0
  17. magic_pdf/para/para_split_v2.py +26 -27
  18. magic_pdf/pdf_parse_union_core.py +34 -6
  19. magic_pdf/pipe/AbsPipe.py +4 -1
  20. magic_pdf/pipe/OCRPipe.py +7 -4
  21. magic_pdf/pipe/TXTPipe.py +7 -4
  22. magic_pdf/pipe/UNIPipe.py +11 -6
  23. magic_pdf/pre_proc/ocr_detect_all_bboxes.py +12 -3
  24. magic_pdf/pre_proc/ocr_dict_merge.py +60 -59
  25. magic_pdf/tools/cli.py +56 -29
  26. magic_pdf/tools/cli_dev.py +61 -64
  27. magic_pdf/tools/common.py +57 -37
  28. magic_pdf/user_api.py +17 -9
  29. {magic_pdf-0.7.1.dist-info → magic_pdf-0.8.1.dist-info}/METADATA +72 -27
  30. {magic_pdf-0.7.1.dist-info → magic_pdf-0.8.1.dist-info}/RECORD +34 -29
  31. {magic_pdf-0.7.1.dist-info → magic_pdf-0.8.1.dist-info}/LICENSE.md +0 -0
  32. {magic_pdf-0.7.1.dist-info → magic_pdf-0.8.1.dist-info}/WHEEL +0 -0
  33. {magic_pdf-0.7.1.dist-info → magic_pdf-0.8.1.dist-info}/entry_points.txt +0 -0
  34. {magic_pdf-0.7.1.dist-info → magic_pdf-0.8.1.dist-info}/top_level.txt +0 -0
magic_pdf/libs/boxbase.py CHANGED
@@ -1,168 +1,166 @@
1
-
2
-
3
- from loguru import logger
4
1
  import math
5
2
 
3
+
6
4
  def _is_in_or_part_overlap(box1, box2) -> bool:
7
- """
8
- 两个bbox是否有部分重叠或者包含
9
- """
5
+ """两个bbox是否有部分重叠或者包含."""
10
6
  if box1 is None or box2 is None:
11
7
  return False
12
-
8
+
13
9
  x0_1, y0_1, x1_1, y1_1 = box1
14
10
  x0_2, y0_2, x1_2, y1_2 = box2
15
11
 
16
12
  return not (x1_1 < x0_2 or # box1在box2的左边
17
13
  x0_1 > x1_2 or # box1在box2的右边
18
14
  y1_1 < y0_2 or # box1在box2的上边
19
- y0_1 > y1_2) # box1在box2的下边
15
+ y0_1 > y1_2) # box1在box2的下边
20
16
 
21
- def _is_in_or_part_overlap_with_area_ratio(box1, box2, area_ratio_threshold=0.6):
22
- """
23
- 判断box1是否在box2里面,或者box1和box2有部分重叠,且重叠面积占box1的比例超过area_ratio_threshold
24
-
25
- """
17
+
18
+ def _is_in_or_part_overlap_with_area_ratio(box1,
19
+ box2,
20
+ area_ratio_threshold=0.6):
21
+ """判断box1是否在box2里面,或者box1和box2有部分重叠,且重叠面积占box1的比例超过area_ratio_threshold."""
26
22
  if box1 is None or box2 is None:
27
23
  return False
28
-
24
+
29
25
  x0_1, y0_1, x1_1, y1_1 = box1
30
26
  x0_2, y0_2, x1_2, y1_2 = box2
31
27
 
32
28
  if not _is_in_or_part_overlap(box1, box2):
33
29
  return False
34
-
30
+
35
31
  # 计算重叠面积
36
32
  x_left = max(x0_1, x0_2)
37
33
  y_top = max(y0_1, y0_2)
38
34
  x_right = min(x1_1, x1_2)
39
35
  y_bottom = min(y1_1, y1_2)
40
36
  overlap_area = (x_right - x_left) * (y_bottom - y_top)
41
-
37
+
42
38
  # 计算box1的面积
43
39
  box1_area = (x1_1 - x0_1) * (y1_1 - y0_1)
44
-
40
+
45
41
  return overlap_area / box1_area > area_ratio_threshold
46
-
47
-
42
+
43
+
48
44
  def _is_in(box1, box2) -> bool:
49
- """
50
- box1是否完全在box2里面
51
- """
45
+ """box1是否完全在box2里面."""
52
46
  x0_1, y0_1, x1_1, y1_1 = box1
53
47
  x0_2, y0_2, x1_2, y1_2 = box2
54
48
 
55
49
  return (x0_1 >= x0_2 and # box1的左边界不在box2的左边外
56
50
  y0_1 >= y0_2 and # box1的上边界不在box2的上边外
57
51
  x1_1 <= x1_2 and # box1的右边界不在box2的右边外
58
- y1_1 <= y1_2) # box1的下边界不在box2的下边外
59
-
52
+ y1_1 <= y1_2) # box1的下边界不在box2的下边外
53
+
54
+
60
55
  def _is_part_overlap(box1, box2) -> bool:
61
- """
62
- 两个bbox是否有部分重叠,但不完全包含
63
- """
56
+ """两个bbox是否有部分重叠,但不完全包含."""
64
57
  if box1 is None or box2 is None:
65
58
  return False
66
-
59
+
67
60
  return _is_in_or_part_overlap(box1, box2) and not _is_in(box1, box2)
68
61
 
62
+
69
63
  def _left_intersect(left_box, right_box):
70
- "检查两个box的左边界是否有交集,也就是left_box的右边界是否在right_box的左边界内"
64
+ """检查两个box的左边界是否有交集,也就是left_box的右边界是否在right_box的左边界内."""
71
65
  if left_box is None or right_box is None:
72
66
  return False
73
-
67
+
74
68
  x0_1, y0_1, x1_1, y1_1 = left_box
75
69
  x0_2, y0_2, x1_2, y1_2 = right_box
76
-
77
- return x1_1>x0_2 and x0_1<x0_2 and (y0_1<=y0_2<=y1_1 or y0_1<=y1_2<=y1_1)
70
+
71
+ return x1_1 > x0_2 and x0_1 < x0_2 and (y0_1 <= y0_2 <= y1_1
72
+ or y0_1 <= y1_2 <= y1_1)
73
+
78
74
 
79
75
  def _right_intersect(left_box, right_box):
80
- """
81
- 检查box是否在右侧边界有交集,也就是left_box的左边界是否在right_box的右边界内
82
- """
76
+ """检查box是否在右侧边界有交集,也就是left_box的左边界是否在right_box的右边界内."""
83
77
  if left_box is None or right_box is None:
84
78
  return False
85
-
79
+
86
80
  x0_1, y0_1, x1_1, y1_1 = left_box
87
81
  x0_2, y0_2, x1_2, y1_2 = right_box
88
-
89
- return x0_1<x1_2 and x1_1>x1_2 and (y0_1<=y0_2<=y1_1 or y0_1<=y1_2<=y1_1)
82
+
83
+ return x0_1 < x1_2 and x1_1 > x1_2 and (y0_1 <= y0_2 <= y1_1
84
+ or y0_1 <= y1_2 <= y1_1)
90
85
 
91
86
 
92
87
  def _is_vertical_full_overlap(box1, box2, x_torlence=2):
93
- """
94
- x方向上:要么box1包含box2, 要么box2包含box1。不能部分包含
95
- y方向上:box1和box2有重叠
96
- """
88
+ """x方向上:要么box1包含box2, 要么box2包含box1。不能部分包含 y方向上:box1和box2有重叠."""
97
89
  # 解析box的坐标
98
90
  x11, y11, x12, y12 = box1 # 左上角和右下角的坐标 (x1, y1, x2, y2)
99
91
  x21, y21, x22, y22 = box2
100
92
 
101
93
  # 在x轴方向上,box1是否包含box2 或 box2包含box1
102
- contains_in_x = (x11-x_torlence <= x21 and x12+x_torlence >= x22) or (x21-x_torlence <= x11 and x22+x_torlence >= x12)
94
+ contains_in_x = (x11 - x_torlence <= x21 and x12 + x_torlence >= x22) or (
95
+ x21 - x_torlence <= x11 and x22 + x_torlence >= x12)
103
96
 
104
97
  # 在y轴方向上,box1和box2是否有重叠
105
98
  overlap_in_y = not (y12 < y21 or y11 > y22)
106
99
 
107
100
  return contains_in_x and overlap_in_y
108
-
101
+
109
102
 
110
103
  def _is_bottom_full_overlap(box1, box2, y_tolerance=2):
111
- """
112
- 检查box1下方和box2的上方有轻微的重叠,轻微程度收到y_tolerance的限制
113
- 这个函数和_is_vertical-full_overlap的区别是,这个函数允许box1和box2在x方向上有轻微的重叠,允许一定的模糊度
114
- """
104
+ """检查box1下方和box2的上方有轻微的重叠,轻微程度收到y_tolerance的限制 这个函数和_is_vertical-
105
+ full_overlap的区别是,这个函数允许box1box2在x方向上有轻微的重叠,允许一定的模糊度."""
115
106
  if box1 is None or box2 is None:
116
107
  return False
117
-
108
+
118
109
  x0_1, y0_1, x1_1, y1_1 = box1
119
110
  x0_2, y0_2, x1_2, y1_2 = box2
120
111
  tolerance_margin = 2
121
- is_xdir_full_overlap = ((x0_1-tolerance_margin<=x0_2<=x1_1+tolerance_margin and x0_1-tolerance_margin<=x1_2<=x1_1+tolerance_margin) or (x0_2-tolerance_margin<=x0_1<=x1_2+tolerance_margin and x0_2-tolerance_margin<=x1_1<=x1_2+tolerance_margin))
122
-
123
- return y0_2<y1_1 and 0<(y1_1-y0_2)<y_tolerance and is_xdir_full_overlap
112
+ is_xdir_full_overlap = (
113
+ (x0_1 - tolerance_margin <= x0_2 <= x1_1 + tolerance_margin
114
+ and x0_1 - tolerance_margin <= x1_2 <= x1_1 + tolerance_margin)
115
+ or (x0_2 - tolerance_margin <= x0_1 <= x1_2 + tolerance_margin
116
+ and x0_2 - tolerance_margin <= x1_1 <= x1_2 + tolerance_margin))
117
+
118
+ return y0_2 < y1_1 and 0 < (y1_1 -
119
+ y0_2) < y_tolerance and is_xdir_full_overlap
120
+
121
+
122
+ def _is_left_overlap(
123
+ box1,
124
+ box2,
125
+ ):
126
+ """检查box1的左侧是否和box2有重叠 在Y方向上可以是部分重叠或者是完全重叠。不分box1和box2的上下关系,也就是无论box1在box2下
127
+ 方还是box2在box1下方,都可以检测到重叠。 X方向上."""
124
128
 
125
- def _is_left_overlap(box1, box2,):
126
- """
127
- 检查box1的左侧是否和box2有重叠
128
- 在Y方向上可以是部分重叠或者是完全重叠。不分box1和box2的上下关系,也就是无论box1在box2下方还是box2在box1下方,都可以检测到重叠。
129
- X方向上
130
- """
131
129
  def __overlap_y(Ay1, Ay2, By1, By2):
132
130
  return max(0, min(Ay2, By2) - max(Ay1, By1))
133
-
131
+
134
132
  if box1 is None or box2 is None:
135
133
  return False
136
-
134
+
137
135
  x0_1, y0_1, x1_1, y1_1 = box1
138
136
  x0_2, y0_2, x1_2, y1_2 = box2
139
-
137
+
140
138
  y_overlap_len = __overlap_y(y0_1, y1_1, y0_2, y1_2)
141
- ratio_1 = 1.0 * y_overlap_len / (y1_1 - y0_1) if y1_1-y0_1!=0 else 0
142
- ratio_2 = 1.0 * y_overlap_len / (y1_2 - y0_2) if y1_2-y0_2!=0 else 0
139
+ ratio_1 = 1.0 * y_overlap_len / (y1_1 - y0_1) if y1_1 - y0_1 != 0 else 0
140
+ ratio_2 = 1.0 * y_overlap_len / (y1_2 - y0_2) if y1_2 - y0_2 != 0 else 0
143
141
  vertical_overlap_cond = ratio_1 >= 0.5 or ratio_2 >= 0.5
144
-
145
- #vertical_overlap_cond = y0_1<=y0_2<=y1_1 or y0_1<=y1_2<=y1_1 or y0_2<=y0_1<=y1_2 or y0_2<=y1_1<=y1_2
146
- return x0_1<=x0_2<=x1_1 and vertical_overlap_cond
142
+
143
+ # vertical_overlap_cond = y0_1<=y0_2<=y1_1 or y0_1<=y1_2<=y1_1 or y0_2<=y0_1<=y1_2 or y0_2<=y1_1<=y1_2
144
+ return x0_1 <= x0_2 <= x1_1 and vertical_overlap_cond
147
145
 
148
146
 
149
- def __is_overlaps_y_exceeds_threshold(bbox1, bbox2, overlap_ratio_threshold=0.8):
147
+ def __is_overlaps_y_exceeds_threshold(bbox1,
148
+ bbox2,
149
+ overlap_ratio_threshold=0.8):
150
150
  """检查两个bbox在y轴上是否有重叠,并且该重叠区域的高度占两个bbox高度更低的那个超过80%"""
151
151
  _, y0_1, _, y1_1 = bbox1
152
152
  _, y0_2, _, y1_2 = bbox2
153
153
 
154
154
  overlap = max(0, min(y1_1, y1_2) - max(y0_1, y0_2))
155
155
  height1, height2 = y1_1 - y0_1, y1_2 - y0_2
156
- max_height = max(height1, height2)
156
+ # max_height = max(height1, height2)
157
157
  min_height = min(height1, height2)
158
158
 
159
159
  return (overlap / min_height) > overlap_ratio_threshold
160
160
 
161
161
 
162
-
163
162
  def calculate_iou(bbox1, bbox2):
164
- """
165
- 计算两个边界框的交并比(IOU)。
163
+ """计算两个边界框的交并比(IOU)。
166
164
 
167
165
  Args:
168
166
  bbox1 (list[float]): 第一个边界框的坐标,格式为 [x1, y1, x2, y2],其中 (x1, y1) 为左上角坐标,(x2, y2) 为右下角坐标。
@@ -170,7 +168,6 @@ def calculate_iou(bbox1, bbox2):
170
168
 
171
169
  Returns:
172
170
  float: 两个边界框的交并比(IOU),取值范围为 [0, 1]。
173
-
174
171
  """
175
172
  # Determine the coordinates of the intersection rectangle
176
173
  x_left = max(bbox1[0], bbox2[0])
@@ -188,16 +185,15 @@ def calculate_iou(bbox1, bbox2):
188
185
  bbox1_area = (bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1])
189
186
  bbox2_area = (bbox2[2] - bbox2[0]) * (bbox2[3] - bbox2[1])
190
187
 
191
- # Compute the intersection over union by taking the intersection area
188
+ # Compute the intersection over union by taking the intersection area
192
189
  # and dividing it by the sum of both areas minus the intersection area
193
- iou = intersection_area / float(bbox1_area + bbox2_area - intersection_area)
190
+ iou = intersection_area / float(bbox1_area + bbox2_area -
191
+ intersection_area)
194
192
  return iou
195
193
 
196
194
 
197
195
  def calculate_overlap_area_2_minbox_area_ratio(bbox1, bbox2):
198
- """
199
- 计算box1和box2的重叠面积占最小面积的box的比例
200
- """
196
+ """计算box1和box2的重叠面积占最小面积的box的比例."""
201
197
  # Determine the coordinates of the intersection rectangle
202
198
  x_left = max(bbox1[0], bbox2[0])
203
199
  y_top = max(bbox1[1], bbox2[1])
@@ -209,16 +205,16 @@ def calculate_overlap_area_2_minbox_area_ratio(bbox1, bbox2):
209
205
 
210
206
  # The area of overlap area
211
207
  intersection_area = (x_right - x_left) * (y_bottom - y_top)
212
- min_box_area = min([(bbox1[2]-bbox1[0])*(bbox1[3]-bbox1[1]), (bbox2[3]-bbox2[1])*(bbox2[2]-bbox2[0])])
213
- if min_box_area==0:
208
+ min_box_area = min([(bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1]),
209
+ (bbox2[3] - bbox2[1]) * (bbox2[2] - bbox2[0])])
210
+ if min_box_area == 0:
214
211
  return 0
215
212
  else:
216
213
  return intersection_area / min_box_area
217
214
 
215
+
218
216
  def calculate_overlap_area_in_bbox1_area_ratio(bbox1, bbox2):
219
- """
220
- 计算box1和box2的重叠面积占bbox1的比例
221
- """
217
+ """计算box1和box2的重叠面积占bbox1的比例."""
222
218
  # Determine the coordinates of the intersection rectangle
223
219
  x_left = max(bbox1[0], bbox2[0])
224
220
  y_top = max(bbox1[1], bbox2[1])
@@ -230,7 +226,7 @@ def calculate_overlap_area_in_bbox1_area_ratio(bbox1, bbox2):
230
226
 
231
227
  # The area of overlap area
232
228
  intersection_area = (x_right - x_left) * (y_bottom - y_top)
233
- bbox1_area = (bbox1[2]-bbox1[0])*(bbox1[3]-bbox1[1])
229
+ bbox1_area = (bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1])
234
230
  if bbox1_area == 0:
235
231
  return 0
236
232
  else:
@@ -238,11 +234,8 @@ def calculate_overlap_area_in_bbox1_area_ratio(bbox1, bbox2):
238
234
 
239
235
 
240
236
  def get_minbox_if_overlap_by_ratio(bbox1, bbox2, ratio):
241
- """
242
- 通过calculate_overlap_area_2_minbox_area_ratio计算两个bbox重叠的面积占最小面积的box的比例
243
- 如果比例大于ratio,则返回小的那个bbox,
244
- 否则返回None
245
- """
237
+ """通过calculate_overlap_area_2_minbox_area_ratio计算两个bbox重叠的面积占最小面积的box的比例
238
+ 如果比例大于ratio,则返回小的那个bbox, 否则返回None."""
246
239
  x1_min, y1_min, x1_max, y1_max = bbox1
247
240
  x2_min, y2_min, x2_max, y2_max = bbox2
248
241
  area1 = (x1_max - x1_min) * (y1_max - y1_min)
@@ -256,89 +249,118 @@ def get_minbox_if_overlap_by_ratio(bbox1, bbox2, ratio):
256
249
  else:
257
250
  return None
258
251
 
259
- def get_bbox_in_boundry(bboxes:list, boundry:tuple)-> list:
260
- x0, y0, x1, y1 = boundry
261
- new_boxes = [box for box in bboxes if box[0] >= x0 and box[1] >= y0 and box[2] <= x1 and box[3] <= y1]
252
+
253
+ def get_bbox_in_boundary(bboxes: list, boundary: tuple) -> list:
254
+ x0, y0, x1, y1 = boundary
255
+ new_boxes = [
256
+ box for box in bboxes
257
+ if box[0] >= x0 and box[1] >= y0 and box[2] <= x1 and box[3] <= y1
258
+ ]
262
259
  return new_boxes
263
260
 
264
261
 
265
262
  def is_vbox_on_side(bbox, width, height, side_threshold=0.2):
266
- """
267
- 判断一个bbox是否在pdf页面的边缘
268
- """
263
+ """判断一个bbox是否在pdf页面的边缘."""
269
264
  x0, x1 = bbox[0], bbox[2]
270
- if x1<=width*side_threshold or x0>=width*(1-side_threshold):
265
+ if x1 <= width * side_threshold or x0 >= width * (1 - side_threshold):
271
266
  return True
272
267
  return False
273
268
 
269
+
274
270
  def find_top_nearest_text_bbox(pymu_blocks, obj_bbox):
275
271
  tolerance_margin = 4
276
- top_boxes = [box for box in pymu_blocks if obj_bbox[1]-box['bbox'][3] >=-tolerance_margin and not _is_in(box['bbox'], obj_bbox)]
272
+ top_boxes = [
273
+ box for box in pymu_blocks
274
+ if obj_bbox[1] - box['bbox'][3] >= -tolerance_margin
275
+ and not _is_in(box['bbox'], obj_bbox)
276
+ ]
277
277
  # 然后找到X方向上有互相重叠的
278
- top_boxes = [box for box in top_boxes if any([obj_bbox[0]-tolerance_margin <=box['bbox'][0]<=obj_bbox[2]+tolerance_margin,
279
- obj_bbox[0]-tolerance_margin <=box['bbox'][2]<=obj_bbox[2]+tolerance_margin,
280
- box['bbox'][0]-tolerance_margin <=obj_bbox[0]<=box['bbox'][2]+tolerance_margin,
281
- box['bbox'][0]-tolerance_margin <=obj_bbox[2]<=box['bbox'][2]+tolerance_margin
282
- ])]
283
-
278
+ top_boxes = [
279
+ box for box in top_boxes if any([
280
+ obj_bbox[0] - tolerance_margin <= box['bbox'][0] <= obj_bbox[2] +
281
+ tolerance_margin, obj_bbox[0] -
282
+ tolerance_margin <= box['bbox'][2] <= obj_bbox[2] +
283
+ tolerance_margin, box['bbox'][0] -
284
+ tolerance_margin <= obj_bbox[0] <= box['bbox'][2] +
285
+ tolerance_margin, box['bbox'][0] -
286
+ tolerance_margin <= obj_bbox[2] <= box['bbox'][2] +
287
+ tolerance_margin
288
+ ])
289
+ ]
290
+
284
291
  # 然后找到y1最大的那个
285
- if len(top_boxes)>0:
292
+ if len(top_boxes) > 0:
286
293
  top_boxes.sort(key=lambda x: x['bbox'][3], reverse=True)
287
294
  return top_boxes[0]
288
295
  else:
289
296
  return None
290
-
297
+
291
298
 
292
299
  def find_bottom_nearest_text_bbox(pymu_blocks, obj_bbox):
293
- bottom_boxes = [box for box in pymu_blocks if box['bbox'][1] - obj_bbox[3]>=-2 and not _is_in(box['bbox'], obj_bbox)]
300
+ bottom_boxes = [
301
+ box for box in pymu_blocks if box['bbox'][1] -
302
+ obj_bbox[3] >= -2 and not _is_in(box['bbox'], obj_bbox)
303
+ ]
294
304
  # 然后找到X方向上有互相重叠的
295
- bottom_boxes = [box for box in bottom_boxes if any([obj_bbox[0]-2 <=box['bbox'][0]<=obj_bbox[2]+2,
296
- obj_bbox[0]-2 <=box['bbox'][2]<=obj_bbox[2]+2,
297
- box['bbox'][0]-2 <=obj_bbox[0]<=box['bbox'][2]+2,
298
- box['bbox'][0]-2 <=obj_bbox[2]<=box['bbox'][2]+2
299
- ])]
300
-
305
+ bottom_boxes = [
306
+ box for box in bottom_boxes if any([
307
+ obj_bbox[0] - 2 <= box['bbox'][0] <= obj_bbox[2] + 2, obj_bbox[0] -
308
+ 2 <= box['bbox'][2] <= obj_bbox[2] + 2, box['bbox'][0] -
309
+ 2 <= obj_bbox[0] <= box['bbox'][2] + 2, box['bbox'][0] -
310
+ 2 <= obj_bbox[2] <= box['bbox'][2] + 2
311
+ ])
312
+ ]
313
+
301
314
  # 然后找到y0最小的那个
302
- if len(bottom_boxes)>0:
315
+ if len(bottom_boxes) > 0:
303
316
  bottom_boxes.sort(key=lambda x: x['bbox'][1], reverse=False)
304
317
  return bottom_boxes[0]
305
318
  else:
306
319
  return None
307
320
 
321
+
308
322
  def find_left_nearest_text_bbox(pymu_blocks, obj_bbox):
309
- """
310
- 寻找左侧最近的文本block
311
- """
312
- left_boxes = [box for box in pymu_blocks if obj_bbox[0]-box['bbox'][2]>=-2 and not _is_in(box['bbox'], obj_bbox)]
323
+ """寻找左侧最近的文本block."""
324
+ left_boxes = [
325
+ box for box in pymu_blocks if obj_bbox[0] -
326
+ box['bbox'][2] >= -2 and not _is_in(box['bbox'], obj_bbox)
327
+ ]
313
328
  # 然后找到X方向上有互相重叠的
314
- left_boxes = [box for box in left_boxes if any([obj_bbox[1]-2 <=box['bbox'][1]<=obj_bbox[3]+2,
315
- obj_bbox[1]-2 <=box['bbox'][3]<=obj_bbox[3]+2,
316
- box['bbox'][1]-2 <=obj_bbox[1]<=box['bbox'][3]+2,
317
- box['bbox'][1]-2 <=obj_bbox[3]<=box['bbox'][3]+2
318
- ])]
319
-
329
+ left_boxes = [
330
+ box for box in left_boxes if any([
331
+ obj_bbox[1] - 2 <= box['bbox'][1] <= obj_bbox[3] + 2, obj_bbox[1] -
332
+ 2 <= box['bbox'][3] <= obj_bbox[3] + 2, box['bbox'][1] -
333
+ 2 <= obj_bbox[1] <= box['bbox'][3] + 2, box['bbox'][1] -
334
+ 2 <= obj_bbox[3] <= box['bbox'][3] + 2
335
+ ])
336
+ ]
337
+
320
338
  # 然后找到x1最大的那个
321
- if len(left_boxes)>0:
339
+ if len(left_boxes) > 0:
322
340
  left_boxes.sort(key=lambda x: x['bbox'][2], reverse=True)
323
341
  return left_boxes[0]
324
342
  else:
325
343
  return None
326
-
344
+
327
345
 
328
346
  def find_right_nearest_text_bbox(pymu_blocks, obj_bbox):
329
- """
330
- 寻找右侧最近的文本block
331
- """
332
- right_boxes = [box for box in pymu_blocks if box['bbox'][0]-obj_bbox[2]>=-2 and not _is_in(box['bbox'], obj_bbox)]
347
+ """寻找右侧最近的文本block."""
348
+ right_boxes = [
349
+ box for box in pymu_blocks if box['bbox'][0] -
350
+ obj_bbox[2] >= -2 and not _is_in(box['bbox'], obj_bbox)
351
+ ]
333
352
  # 然后找到X方向上有互相重叠的
334
- right_boxes = [box for box in right_boxes if any([obj_bbox[1]-2 <=box['bbox'][1]<=obj_bbox[3]+2,
335
- obj_bbox[1]-2 <=box['bbox'][3]<=obj_bbox[3]+2,
336
- box['bbox'][1]-2 <=obj_bbox[1]<=box['bbox'][3]+2,
337
- box['bbox'][1]-2 <=obj_bbox[3]<=box['bbox'][3]+2
338
- ])]
339
-
353
+ right_boxes = [
354
+ box for box in right_boxes if any([
355
+ obj_bbox[1] - 2 <= box['bbox'][1] <= obj_bbox[3] + 2, obj_bbox[1] -
356
+ 2 <= box['bbox'][3] <= obj_bbox[3] + 2, box['bbox'][1] -
357
+ 2 <= obj_bbox[1] <= box['bbox'][3] + 2, box['bbox'][1] -
358
+ 2 <= obj_bbox[3] <= box['bbox'][3] + 2
359
+ ])
360
+ ]
361
+
340
362
  # 然后找到x0最小的那个
341
- if len(right_boxes)>0:
363
+ if len(right_boxes) > 0:
342
364
  right_boxes.sort(key=lambda x: x['bbox'][0], reverse=False)
343
365
  return right_boxes[0]
344
366
  else:
@@ -346,8 +368,7 @@ def find_right_nearest_text_bbox(pymu_blocks, obj_bbox):
346
368
 
347
369
 
348
370
  def bbox_relative_pos(bbox1, bbox2):
349
- """
350
- 判断两个矩形框的相对位置关系
371
+ """判断两个矩形框的相对位置关系.
351
372
 
352
373
  Args:
353
374
  bbox1: 一个四元组,表示第一个矩形框的左上角和右下角的坐标,格式为(x1, y1, x1b, y1b)
@@ -357,20 +378,19 @@ def bbox_relative_pos(bbox1, bbox2):
357
378
  一个四元组,表示矩形框1相对于矩形框2的位置关系,格式为(left, right, bottom, top)
358
379
  其中,left表示矩形框1是否在矩形框2的左侧,right表示矩形框1是否在矩形框2的右侧,
359
380
  bottom表示矩形框1是否在矩形框2的下方,top表示矩形框1是否在矩形框2的上方
360
-
361
381
  """
362
382
  x1, y1, x1b, y1b = bbox1
363
383
  x2, y2, x2b, y2b = bbox2
364
-
384
+
365
385
  left = x2b < x1
366
386
  right = x1b < x2
367
387
  bottom = y2b < y1
368
388
  top = y1b < y2
369
389
  return left, right, bottom, top
370
-
390
+
391
+
371
392
  def bbox_distance(bbox1, bbox2):
372
- """
373
- 计算两个矩形框的距离。
393
+ """计算两个矩形框的距离。
374
394
 
375
395
  Args:
376
396
  bbox1 (tuple): 第一个矩形框的坐标,格式为 (x1, y1, x2, y2),其中 (x1, y1) 为左上角坐标,(x2, y2) 为右下角坐标。
@@ -378,16 +398,17 @@ def bbox_distance(bbox1, bbox2):
378
398
 
379
399
  Returns:
380
400
  float: 矩形框之间的距离。
381
-
382
401
  """
402
+
383
403
  def dist(point1, point2):
384
- return math.sqrt((point1[0]-point2[0])**2 + (point1[1]-point2[1])**2)
385
-
404
+ return math.sqrt((point1[0] - point2[0])**2 +
405
+ (point1[1] - point2[1])**2)
406
+
386
407
  x1, y1, x1b, y1b = bbox1
387
408
  x2, y2, x2b, y2b = bbox2
388
-
409
+
389
410
  left, right, bottom, top = bbox_relative_pos(bbox1, bbox2)
390
-
411
+
391
412
  if top and left:
392
413
  return dist((x1, y1b), (x2b, y2))
393
414
  elif left and bottom:
@@ -404,5 +425,23 @@ def bbox_distance(bbox1, bbox2):
404
425
  return y1 - y2b
405
426
  elif top:
406
427
  return y2 - y1b
407
- else: # rectangles intersect
408
- return 0
428
+ return 0.0
429
+
430
+
431
+ def box_area(bbox):
432
+ return (bbox[2] - bbox[0]) * (bbox[3] - bbox[1])
433
+
434
+
435
+ def get_overlap_area(bbox1, bbox2):
436
+ """计算box1和box2的重叠面积占bbox1的比例."""
437
+ # Determine the coordinates of the intersection rectangle
438
+ x_left = max(bbox1[0], bbox2[0])
439
+ y_top = max(bbox1[1], bbox2[1])
440
+ x_right = min(bbox1[2], bbox2[2])
441
+ y_bottom = min(bbox1[3], bbox2[3])
442
+
443
+ if x_right < x_left or y_bottom < y_top:
444
+ return 0.0
445
+
446
+ # The area of overlap area
447
+ return (x_right - x_left) * (y_bottom - y_top)