table_correct.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. import math
  2. import cmath
  3. import traceback
  4. import numpy as np
  5. import cv2
  6. # 图片旋转
  7. from format_convert.judge_platform import get_platform
  8. def rotate_bound(image, angle):
  9. try:
  10. # 获取宽高
  11. (h, w) = image.shape[:2]
  12. (cX, cY) = (w // 2, h // 2)
  13. # 提取旋转矩阵 sin cos
  14. M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
  15. cos = np.abs(M[0, 0])
  16. sin = np.abs(M[0, 1])
  17. # 计算图像的新边界尺寸
  18. nW = int((h * sin) + (w * cos))
  19. # nH = int((h * cos) + (w * sin))
  20. nH = h
  21. # 调整旋转矩阵
  22. M[0, 2] += (nW / 2) - cX
  23. M[1, 2] += (nH / 2) - cY
  24. return cv2.warpAffine(image, M, (nW, nH),flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
  25. except Exception as e:
  26. print("rotate_bound", e)
  27. # 获取图片旋转角度
  28. def get_minAreaRect(image):
  29. try:
  30. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  31. ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
  32. if get_platform() == "Windows":
  33. cv2.imshow("binary", binary)
  34. cv2.waitKey(0)
  35. contours, hier = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
  36. # 绘制矩形
  37. cv2.drawContours(image, contours, 0, (255, 0, 255), 3)
  38. if get_platform() == "Windows":
  39. cv2.imshow("image", image)
  40. cv2.waitKey(0)
  41. for c in contours: #遍历轮廓
  42. rect = cv2.minAreaRect(c) #生成最小外接矩形
  43. box_ = cv2.boxPoints(rect)
  44. h = abs(box_[3, 1] - box_[1, 1])
  45. w = abs(box_[3, 0] - box_[1, 0])
  46. print("宽,高", w, h)
  47. # 只保留需要的轮廓
  48. if h > 3000 or w > 2200:
  49. continue
  50. if h < 2500 or w < 1500:
  51. continue
  52. # 计算最小面积矩形的坐标
  53. box = cv2.boxPoints(rect)
  54. # 将坐标规范化为整数
  55. box = np.int0(box)
  56. # 获取矩形相对于水平面的角度
  57. angle = rect[2]
  58. if angle > 0:
  59. if abs(angle) > 45:
  60. angle = 90 - abs(angle)
  61. else:
  62. if abs(angle) > 45:
  63. angle = (90 - abs(angle))
  64. print("轮廓数量", len(contours))
  65. return image, box, angle
  66. except Exception as e:
  67. print("get_minAreaRect", traceback.print_exc())
  68. return [-1], [-1], [-1]
  69. def get_table_line(image):
  70. # 二值化
  71. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  72. binary = cv2.adaptiveThreshold(~gray, 255,
  73. cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 203, -10)
  74. # cv2.imshow("cell", binary)
  75. # cv2.waitKey(0)
  76. # 轮廓
  77. kernel_row = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], np.float32)
  78. kernel_col = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], np.float32)
  79. # Sobel
  80. # kernel_row = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]], np.float32)
  81. # kernel_col = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], np.float32)
  82. # binary = cv2.filter2D(binary, -1, kernel=kernel)
  83. binary_row = cv2.filter2D(binary, -1, kernel=kernel_row)
  84. binary_col = cv2.filter2D(binary, -1, kernel=kernel_col)
  85. # cv2.imshow("custom_blur_demo", binary)
  86. # cv2.waitKey(0)
  87. # rows, cols = binary.shape
  88. # scale = 20
  89. # # 识别横线
  90. # kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (cols//scale, 1))
  91. # erodedcol = cv2.erode(binary_row, kernel, iterations=1)
  92. # cv2.imshow("Eroded Image", erodedcol)
  93. # cv2.waitKey(0)
  94. # dilatedcol = cv2.dilate(erodedcol, kernel, iterations=3)
  95. # cv2.imshow("Dilated Image", dilatedcol)
  96. # cv2.waitKey(0)
  97. #
  98. # # 识别竖线
  99. # scale = 20
  100. # kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, rows//scale))
  101. # erodedrow = cv2.erode(binary_col, kernel, iterations=1)
  102. # cv2.imshow("Eroded Image", erodedrow)
  103. # cv2.waitKey(0)
  104. # dilatedrow = cv2.dilate(erodedrow, kernel, iterations=3)
  105. # cv2.imshow("Dilated Image", dilatedrow)
  106. # cv2.waitKey(0)
  107. #
  108. # # 标识表格
  109. # merge = cv2.add(dilatedcol, dilatedrow)
  110. # cv2.imshow("add Image", merge)
  111. # cv2.imwrite('table_outline.jpg', merge)
  112. # cv2.waitKey(0)
  113. return binary_row
  114. def detect_line(img):
  115. try:
  116. gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  117. edges = cv2.Canny(gray, 100, 1000)
  118. # cv2.imshow("edges", edges)
  119. # cv2.waitKey(0)
  120. lines = cv2.HoughLines(edges, 1, np.pi/180, 200)
  121. if lines is None or len(lines) == 0:
  122. return 0
  123. angle_list = []
  124. for i in range(len(lines)):
  125. # 第一个元素是距离rho
  126. rho = lines[i][0][0]
  127. # 第二个元素是角度theta
  128. theta = lines[i][0][1]
  129. a = np.cos(theta)
  130. b = np.sin(theta)
  131. x0 = a*rho
  132. y0 = b*rho
  133. x1 = float(x0 + 1000*(-b))
  134. y1 = float(y0 + 1000*a)
  135. x2 = float(x0 - 1000*(-b))
  136. y2 = float(y0 - 1000*a)
  137. if x2-x1 == 0 or y2-y1 == 0 or x2-x1 <= 0.01 or y2-y1 <= 0.01:
  138. continue
  139. k = -(y2-y1) / (x2-x1)
  140. if abs(k) <= 5:
  141. # h = math.atan(k)
  142. # angle = math.degrees(h)
  143. angle = np.arctan(k) * (180/math.pi)
  144. # 调整
  145. angle_list.append(angle)
  146. # print(angle)
  147. # cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
  148. angle_sum = 0
  149. for a in angle_list:
  150. angle_sum += a
  151. angle_avg = angle_sum/len(angle_list)
  152. print("angle_avg", angle_avg)
  153. return angle_avg
  154. except Exception as e:
  155. print("detect_line", e)
  156. def get_rotated_image_old(image, output_path):
  157. try:
  158. angle = detect_line(image)
  159. if angle != 0:
  160. rotated = rotate_bound(image, angle)
  161. # cv2.putText(rotated, "angle: {:.3f} ".format(angle),
  162. # (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
  163. # show the output image
  164. # cv2.imshow("imput", image)
  165. # cv2.waitKey(0)
  166. # cv2.imshow("output", rotated)
  167. # cv2.waitKey(0)
  168. print("[INFO] angle: {:.3f}".format(angle))
  169. cv2.imwrite(output_path, rotated)
  170. return True
  171. else:
  172. print("angle", angle)
  173. return False
  174. except Exception as e:
  175. print("get_rotated_image", e)
  176. return False
  177. def rotate_bound(image, angle):
  178. # 获取宽高
  179. (h, w) = image.shape[:2]
  180. (cX, cY) = (w // 2, h // 2)
  181. # 提取旋转矩阵 sin cos
  182. M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
  183. cos = np.abs(M[0, 0])
  184. sin = np.abs(M[0, 1])
  185. # 计算图像的新边界尺寸
  186. nW = int((h * sin) + (w * cos))
  187. # nH = int((h * cos) + (w * sin))
  188. nH = h
  189. # 调整旋转矩阵
  190. M[0, 2] += (nW / 2) - cX
  191. M[1, 2] += (nH / 2) - cY
  192. return cv2.warpAffine(image, M, (nW, nH),flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
  193. # 获取图片旋转角度
  194. def get_minAreaRect(image):
  195. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  196. gray = cv2.bitwise_not(gray)
  197. thresh = cv2.threshold(gray, 0, 255,
  198. cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
  199. coords = np.column_stack(np.where(thresh > 0))
  200. return cv2.minAreaRect(coords)
  201. def get_rotated_image(image, output_path):
  202. try:
  203. image_temp, box, angle = get_minAreaRect(image)
  204. if angle == [-1]:
  205. return [-1]
  206. # angle = get_minAreaRect(image)[-1]
  207. if abs(angle) >= 15:
  208. angle = 0
  209. rotated = rotate_bound(image, angle)
  210. # cv2.putText(rotated, "angle: {:.2f} ".format(angle),
  211. # (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
  212. # show the output image
  213. # print("[INFO] angle: {:.3f}".format(angle))
  214. if not angle:
  215. cv2.imwrite(output_path, rotated)
  216. # cv2.imshow("input", image)
  217. # cv2.waitKey(0)
  218. # cv2.imshow("output", rotated)
  219. # cv2.waitKey(0)
  220. return True
  221. except cv2.error:
  222. traceback.print_exc()
  223. return [-3]
  224. except Exception as e:
  225. traceback.print_exc()
  226. return [-1]
  227. if __name__ == '__main__':
  228. temp_path = "temp/complex/8.png"
  229. # temp_path = "temp/92d885dcb77411eb914300163e0ae709/92d8ef5eb77411eb914300163e0ae709_pdf_page1.png"
  230. image = cv2.imread(temp_path)
  231. get_rotated_image(image, temp_path)
  232. # test()