table_utils.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import os
  2. import sys
  3. import numpy as np
  4. import cv2
  5. sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../../")
  6. from format_convert.utils import log
  7. def shrink_bbox(img, bbox_list):
  8. def return_first_black_index(image_np):
  9. lower = np.array([0, 0, 0])
  10. upper = np.array([150, 150, 150])
  11. mask = cv2.inRange(image_np, lower, upper)
  12. black_index_list = np.where(mask != 0)
  13. return black_index_list
  14. new_bbox_list = []
  15. for bbox in bbox_list:
  16. img_bbox = img[int(bbox[0][1]):int(bbox[2][1]), int(bbox[0][0]):int(bbox[2][0]), :]
  17. if 0 in img_bbox.shape:
  18. new_bbox_list.append(bbox)
  19. continue
  20. # 左右上下开始扫描,碰到黑像素即停
  21. index_list = return_first_black_index(img_bbox[:, :, :])
  22. if index_list[0].size == 0 or index_list[1].size == 0:
  23. new_bbox_list.append(bbox)
  24. continue
  25. min_h = index_list[0][0]
  26. max_h = index_list[0][-1]
  27. img_bbox1 = np.swapaxes(img_bbox, 0, 1)
  28. index_list = return_first_black_index(img_bbox1[:, :, :])
  29. if index_list[0].size == 0 or index_list[1].size == 0:
  30. new_bbox_list.append(bbox)
  31. continue
  32. min_w = index_list[0][0]
  33. max_w = index_list[0][-1]
  34. real_min_w = bbox[0][0] + min_w
  35. real_max_w = bbox[0][0] + max_w
  36. real_min_h = bbox[0][1] + min_h
  37. real_max_h = bbox[0][1] + max_h
  38. new_bbox = [[real_min_w, real_min_h], [real_min_w, real_max_h], [real_max_w, real_max_h], [real_max_w, real_min_h]]
  39. new_bbox_list.append(new_bbox)
  40. # cv2.imshow('img', img_bbox)
  41. # cv2.imshow('shrink', img[int(new_bbox[0][1]):int(new_bbox[2][1]), int(new_bbox[0][0]):int(new_bbox[2][0]), :])
  42. # cv2.waitKey(0)
  43. return new_bbox_list
  44. def split_bbox(img, bbox, bbox_text_dict):
  45. text = bbox_text_dict.get(str(bbox))
  46. sub_img = img[int(bbox[0][1]):int(bbox[2][1]), int(bbox[0][0]):int(bbox[2][0]), :]
  47. split_line_list = []
  48. last_i_status = 1
  49. # 从左到右遍历img
  50. for i in range(1, sub_img.shape[1]):
  51. # 若这一列黑色像素超过一定值
  52. if np.where(sub_img[:, i, :] < 200)[0].size > sub_img.shape[0]/5:
  53. i_status = 0
  54. else:
  55. i_status = 1
  56. # 异或,上个像素列为黑且这个像素列为白,或上个像素列为白且这个像素列为黑
  57. if last_i_status ^ i_status:
  58. split_line_list.append(int(i))
  59. last_i_status = i_status
  60. # 两条分割线太近的去重
  61. min_len = 5
  62. last_l = split_line_list[0]
  63. temp_list = [split_line_list[0]]
  64. for l in split_line_list[1:]:
  65. if l - last_l > min_len:
  66. temp_list.append(l)
  67. last_l = l
  68. split_line_list = temp_list
  69. # 若两个分割线间无黑像素,则是应该分割的
  70. split_pair_list = []
  71. last_line = split_line_list[0]
  72. for line in split_line_list[1:]:
  73. print('last_line, line', last_line, line, np.where(sub_img[:, last_line:line, :] < 100)[0].size)
  74. if line - last_line >= 10 and np.where(sub_img[:, last_line:line, :] < 100)[0].size < 10:
  75. split_pair_list.append([last_line, line])
  76. last_line = line
  77. print('split_pair_list', split_pair_list)
  78. for l in split_line_list:
  79. l = int(l + bbox[0][0])
  80. cv2.line(img, (l, int(bbox[0][1])), (l, int(bbox[2][1])), (0, 255, 0), 2)
  81. cv2.rectangle(img, (int(bbox[0][0]), int(bbox[0][1])), (int(bbox[2][0]), int(bbox[2][1])),
  82. (0, 0, 255), 1)
  83. cv2.imshow('img', img)
  84. cv2.waitKey(0)
  85. # 分割得到新bbox
  86. split_bbox_list = []
  87. if split_pair_list:
  88. start_line = 0
  89. for line1, line2 in split_pair_list:
  90. w1 = start_line + bbox[0][0]
  91. w2 = line1 + bbox[0][0]
  92. start_line = line2
  93. split_bbox_list.append([[w1, bbox[0][1]], [], [w2, bbox[2][1]], []])
  94. w1 = start_line + bbox[0][0]
  95. w2 = bbox[2][0]
  96. split_bbox_list.append([[w1, bbox[0][1]], [], [w2, bbox[2][1]], []])
  97. print('split_bbox_list', split_bbox_list)
  98. # 计算每个字长度
  99. all_len = 0
  100. bbox_len_list = []
  101. for bbox in split_bbox_list:
  102. _len = abs(bbox[2][0] - bbox[0][0])
  103. all_len += _len
  104. bbox_len_list.append(_len)
  105. single_char_len = all_len / len(text)
  106. # 根据bbox长度和单字长度比例计算得到截取后的text
  107. split_text_list = []
  108. text_start = 0
  109. for _len in bbox_len_list:
  110. text_num = int(_len / single_char_len + 0.5)
  111. text_end = text_start+text_num
  112. if text_end >= len(text):
  113. text_end = len(text)
  114. split_text_list.append(text[text_start:text_end])
  115. text_start = text_end
  116. print('split_text_list', split_text_list)
  117. # 更新bbox_text_dict
  118. for i, bbox in enumerate(split_bbox_list):
  119. bbox_text_dict[str(bbox)] = split_text_list[i]
  120. return split_bbox_list, bbox_text_dict
  121. def count_black(image_np, threshold=150):
  122. lower = np.array([0, 0, 0])
  123. upper = np.array([threshold, threshold, threshold])
  124. mask = cv2.inRange(image_np, lower, upper)
  125. cnt = np.sum(mask != 0)
  126. # print("count color ", cnt)
  127. return cnt
  128. def get_points_by_line(img, row_lines, col_lines):
  129. row_img = np.zeros_like(img[:, :, 0], dtype=np.uint8)
  130. col_img = np.zeros_like(img[:, :, 0], dtype=np.uint8)
  131. for r in row_lines:
  132. cv2.line(row_img, (r[0], r[1]), (r[2], r[3]), (255, 255, 255), 1)
  133. for c in col_lines:
  134. cv2.line(col_img, (c[0], c[1]), (c[2], c[3]), (255, 255, 255), 1)
  135. point_img = np.bitwise_and(row_img, col_img)
  136. # 识别黑白图中的白色交叉点,将横纵坐标取出
  137. ys, xs = np.where(point_img > 0)
  138. points = []
  139. for i in range(len(xs)):
  140. points.append((xs[i], ys[i]))
  141. points.sort(key=lambda x: (x[0], x[1]))
  142. return points
  143. def get_table_bbox_list(img, area_row_lines, area_col_lines, table_location_list, bbox_list):
  144. area_table_bbox_list = []
  145. area_table_cell_list = []
  146. for i in range(len(table_location_list)):
  147. row_lines = area_row_lines[i]
  148. col_lines = area_col_lines[i]
  149. # 求线交点
  150. cross_points = get_points_by_line(img, row_lines, col_lines)
  151. # for p in cross_points:
  152. # cv2.circle(img, p, 2, (0, 0, 255), 2)
  153. # cv2.imshow('cross_points', img)
  154. # 交点分行
  155. cross_points.sort(key=lambda x: (x[1], x[0]))
  156. row_point_list = []
  157. if not cross_points:
  158. area_table_bbox_list.append([])
  159. area_table_cell_list.append([])
  160. continue
  161. current_row = [cross_points[0]]
  162. for p in cross_points[1:]:
  163. if current_row[0][1] == p[1]:
  164. current_row.append(p)
  165. else:
  166. row_point_list.append(current_row)
  167. current_row = [p]
  168. if current_row:
  169. row_point_list.append(current_row)
  170. # bbox以表格格式排列
  171. used_bbox_list = []
  172. row_list = []
  173. row_cell_list = []
  174. for j in range(1, len(row_point_list)):
  175. last_row = row_point_list[j-1]
  176. row = row_point_list[j]
  177. col_list = []
  178. col_cell_list = []
  179. for k in range(1, len(row)):
  180. last_p = last_row[k-1]
  181. p = row[k]
  182. cell = []
  183. for bbox in bbox_list:
  184. if bbox in used_bbox_list:
  185. continue
  186. bbox_h_center = (bbox[0][1]+bbox[2][1]) / 2
  187. bbox_w_center = (bbox[0][0]+bbox[2][0]) / 2
  188. if last_p[1] <= bbox_h_center <= p[1] and last_p[0] <= bbox_w_center <= p[0]:
  189. cell.append(bbox)
  190. used_bbox_list.append(bbox)
  191. col_list.append(cell)
  192. col_cell_list.append([last_p, p])
  193. row_list.append(col_list)
  194. row_cell_list.append(col_cell_list)
  195. area_table_bbox_list.append(row_list)
  196. area_table_cell_list.append(row_cell_list)
  197. return area_table_bbox_list[0], area_table_cell_list[0]