trans_funsd_label.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. # copyright (c) 2022 PaddlePaddle Authors. All Rights Reserve.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import json
  15. import os
  16. import sys
  17. import cv2
  18. import numpy as np
  19. from copy import deepcopy
  20. def trans_poly_to_bbox(poly):
  21. x1 = np.min([p[0] for p in poly])
  22. x2 = np.max([p[0] for p in poly])
  23. y1 = np.min([p[1] for p in poly])
  24. y2 = np.max([p[1] for p in poly])
  25. return [x1, y1, x2, y2]
  26. def get_outer_poly(bbox_list):
  27. x1 = min([bbox[0] for bbox in bbox_list])
  28. y1 = min([bbox[1] for bbox in bbox_list])
  29. x2 = max([bbox[2] for bbox in bbox_list])
  30. y2 = max([bbox[3] for bbox in bbox_list])
  31. return [[x1, y1], [x2, y1], [x2, y2], [x1, y2]]
  32. def load_funsd_label(image_dir, anno_dir):
  33. imgs = os.listdir(image_dir)
  34. annos = os.listdir(anno_dir)
  35. imgs = [img.replace(".png", "") for img in imgs]
  36. annos = [anno.replace(".json", "") for anno in annos]
  37. fn_info_map = dict()
  38. for anno_fn in annos:
  39. res = []
  40. with open(os.path.join(anno_dir, anno_fn + ".json"), "r") as fin:
  41. infos = json.load(fin)
  42. infos = infos["form"]
  43. old_id2new_id_map = dict()
  44. global_new_id = 0
  45. for info in infos:
  46. if info["text"] is None:
  47. continue
  48. words = info["words"]
  49. if len(words) <= 0:
  50. continue
  51. word_idx = 1
  52. curr_bboxes = [words[0]["box"]]
  53. curr_texts = [words[0]["text"]]
  54. while word_idx < len(words):
  55. # switch to a new link
  56. if words[word_idx]["box"][0] + 10 <= words[word_idx - 1][
  57. "box"][2]:
  58. if len("".join(curr_texts[0])) > 0:
  59. res.append({
  60. "transcription": " ".join(curr_texts),
  61. "label": info["label"],
  62. "points": get_outer_poly(curr_bboxes),
  63. "linking": info["linking"],
  64. "id": global_new_id,
  65. })
  66. if info["id"] not in old_id2new_id_map:
  67. old_id2new_id_map[info["id"]] = []
  68. old_id2new_id_map[info["id"]].append(global_new_id)
  69. global_new_id += 1
  70. curr_bboxes = [words[word_idx]["box"]]
  71. curr_texts = [words[word_idx]["text"]]
  72. else:
  73. curr_bboxes.append(words[word_idx]["box"])
  74. curr_texts.append(words[word_idx]["text"])
  75. word_idx += 1
  76. if len("".join(curr_texts[0])) > 0:
  77. res.append({
  78. "transcription": " ".join(curr_texts),
  79. "label": info["label"],
  80. "points": get_outer_poly(curr_bboxes),
  81. "linking": info["linking"],
  82. "id": global_new_id,
  83. })
  84. if info["id"] not in old_id2new_id_map:
  85. old_id2new_id_map[info["id"]] = []
  86. old_id2new_id_map[info["id"]].append(global_new_id)
  87. global_new_id += 1
  88. res = sorted(
  89. res, key=lambda r: (r["points"][0][1], r["points"][0][0]))
  90. for i in range(len(res) - 1):
  91. for j in range(i, 0, -1):
  92. if abs(res[j + 1]["points"][0][1] - res[j]["points"][0][1]) < 20 and \
  93. (res[j + 1]["points"][0][0] < res[j]["points"][0][0]):
  94. tmp = deepcopy(res[j])
  95. res[j] = deepcopy(res[j + 1])
  96. res[j + 1] = deepcopy(tmp)
  97. else:
  98. break
  99. # re-generate unique ids
  100. for idx, r in enumerate(res):
  101. new_links = []
  102. for link in r["linking"]:
  103. # illegal links will be removed
  104. if link[0] not in old_id2new_id_map or link[
  105. 1] not in old_id2new_id_map:
  106. continue
  107. for src in old_id2new_id_map[link[0]]:
  108. for dst in old_id2new_id_map[link[1]]:
  109. new_links.append([src, dst])
  110. res[idx]["linking"] = deepcopy(new_links)
  111. fn_info_map[anno_fn] = res
  112. return fn_info_map
  113. def main():
  114. test_image_dir = "train_data/FUNSD/testing_data/images/"
  115. test_anno_dir = "train_data/FUNSD/testing_data/annotations/"
  116. test_output_dir = "train_data/FUNSD/test.json"
  117. fn_info_map = load_funsd_label(test_image_dir, test_anno_dir)
  118. with open(test_output_dir, "w") as fout:
  119. for fn in fn_info_map:
  120. fout.write(fn + ".png" + "\t" + json.dumps(
  121. fn_info_map[fn], ensure_ascii=False) + "\n")
  122. train_image_dir = "train_data/FUNSD/training_data/images/"
  123. train_anno_dir = "train_data/FUNSD/training_data/annotations/"
  124. train_output_dir = "train_data/FUNSD/train.json"
  125. fn_info_map = load_funsd_label(train_image_dir, train_anno_dir)
  126. with open(train_output_dir, "w") as fout:
  127. for fn in fn_info_map:
  128. fout.write(fn + ".png" + "\t" + json.dumps(
  129. fn_info_map[fn], ensure_ascii=False) + "\n")
  130. print("====ok====")
  131. return
  132. if __name__ == "__main__":
  133. main()