ocr_detect_layout.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. from magic_pdf.libs.boxbase import _is_part_overlap, _is_in
  2. def get_center_point(bbox):
  3. """
  4. 根据边界框坐标信息,计算出该边界框的中心点坐标。
  5. Args:
  6. bbox (list): 边界框坐标信息,包含四个元素,分别为左上角x坐标、左上角y坐标、右下角x坐标、右下角y坐标。
  7. Returns:
  8. list: 中心点坐标信息,包含两个元素,分别为x坐标和y坐标。
  9. """
  10. return [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2]
  11. def get_area(bbox):
  12. """
  13. 根据边界框坐标信息,计算出该边界框的面积。
  14. Args:
  15. bbox (list): 边界框坐标信息,包含四个元素,分别为左上角x坐标、左上角y坐标、右下角x坐标、右下角y坐标。
  16. Returns:
  17. float: 该边界框的面积。
  18. """
  19. return (bbox[2] - bbox[0]) * (bbox[3] - bbox[1])
  20. def adjust_layouts(layout_bboxes):
  21. # 遍历所有布局框
  22. for i in range(len(layout_bboxes)):
  23. # 遍历当前布局框之后的布局框
  24. for j in range(i + 1, len(layout_bboxes)):
  25. # 判断两个布局框是否重叠
  26. if _is_part_overlap(layout_bboxes[i], layout_bboxes[j]):
  27. # 计算每个布局框的中心点坐标和面积
  28. center_i = get_center_point(layout_bboxes[i]["layout_bbox"])
  29. area_i = get_area(layout_bboxes[i]["layout_bbox"])
  30. center_j = get_center_point(layout_bboxes[j]["layout_bbox"])
  31. area_j = get_area(layout_bboxes[j]["layout_bbox"])
  32. # 计算横向和纵向的距离差
  33. dx = abs(center_i[0] - center_j[0])
  34. dy = abs(center_i[1] - center_j[1])
  35. # 较大布局框和较小布局框的赋值
  36. if area_i > area_j:
  37. larger_layout, smaller_layout = layout_bboxes[i], layout_bboxes[j]
  38. else:
  39. larger_layout, smaller_layout = layout_bboxes[j], layout_bboxes[i]
  40. # 根据距离差判断重叠方向并修正边界
  41. if dx > dy: # 左右重叠
  42. if larger_layout["layout_bbox"][0] < smaller_layout["layout_bbox"][2]:
  43. larger_layout["layout_bbox"][0] = smaller_layout["layout_bbox"][2]
  44. else:
  45. larger_layout["layout_bbox"][2] = smaller_layout["layout_bbox"][0]
  46. else: # 上下重叠
  47. if larger_layout["layout_bbox"][1] < smaller_layout["layout_bbox"][3]:
  48. larger_layout["layout_bbox"][1] = smaller_layout["layout_bbox"][3]
  49. else:
  50. larger_layout["layout_bbox"][3] = smaller_layout["layout_bbox"][1]
  51. # 返回排序调整后的布局边界框列表
  52. return layout_bboxes
  53. def layout_detect(layout_info):
  54. """
  55. 对输入的布局信息进行解析,提取出每个子布局的边界框,并对所有子布局进行排序调整。
  56. Args:
  57. layout_info (list): 包含子布局信息的列表,每个子布局信息为字典类型,包含'poly'字段,表示子布局的边界框坐标信息。
  58. Returns:
  59. list: 经过排序调整后的所有子布局边界框信息的列表,每个边界框信息为字典类型,包含'layout_bbox'字段,表示边界框的坐标信息。
  60. """
  61. # 初始化布局边界框列表
  62. layout_bboxes = []
  63. # 遍历每个子布局
  64. for sub_layout in layout_info:
  65. # 提取子布局的边界框坐标信息
  66. x0, y0, _, _, x1, y1, _, _ = sub_layout['poly']
  67. # 创建子布局的边界框字典
  68. layout_bbox = {
  69. "layout_bbox": [x0, y0, x1, y1],
  70. }
  71. # 将子布局的边界框添加到列表中
  72. layout_bboxes.append(layout_bbox)
  73. # 初始化新的布局边界框列表
  74. new_layout_bboxes = []
  75. # 遍历每个布局边界框
  76. for i in range(len(layout_bboxes)):
  77. # 初始化标记变量,用于判断当前边界框是否需要保留
  78. keep = True
  79. # 获取当前边界框的坐标信息
  80. box_i = layout_bboxes[i]["layout_bbox"]
  81. # 遍历其他边界框
  82. for j in range(len(layout_bboxes)):
  83. # 排除当前边界框自身
  84. if i != j:
  85. # 获取其他边界框的坐标信息
  86. box_j = layout_bboxes[j]["layout_bbox"]
  87. # 检测box_i是否被box_j包含
  88. if _is_in(box_i, box_j):
  89. # 如果当前边界框被其他边界框包含,则标记为不需要保留
  90. keep = False
  91. # 跳出内层循环
  92. break
  93. # 如果当前边界框需要保留,则添加到新的布局边界框列表中
  94. if keep:
  95. new_layout_bboxes.append(layout_bboxes[i])
  96. # 对新的布局边界框列表进行排序调整
  97. layout_bboxes = adjust_layouts(new_layout_bboxes)
  98. # 返回排序调整后的布局边界框列表
  99. return layout_bboxes