direction.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import re
  2. import cv2
  3. import numpy as np
  4. from dataclasses import dataclass
  5. from enum import Enum
  6. from typing import Tuple, List
  7. import cv2
  8. from paddleocr import PaddleOCR
  9. from core.line_parser import LineParser
  10. # 枚举
  11. class Direction(Enum):
  12. TOP = 0
  13. RIGHT = 1
  14. BOTTOM = 2
  15. LEFT = 3
  16. # 父类
  17. class OcrAnchor(object):
  18. # anchor的名字, 如身份证号、承办人等
  19. def __init__(self, name: str, d: List[Direction]):
  20. self.name = name
  21. self.direction = d
  22. # 定义枚举字典
  23. def t_func(anchor, c, is_horizontal):
  24. if is_horizontal:
  25. return 0 if anchor[1] < c[1] else 2
  26. else:
  27. return 1 if anchor[0] > c[0] else 3
  28. def l_func(anchor, c, is_horizontal):
  29. if is_horizontal:
  30. return 0 if anchor[0] < c[0] else 2
  31. else:
  32. return 1 if anchor[1] < c[1] else 3
  33. def b_func(anchor, c, is_horizontal):
  34. if is_horizontal:
  35. return 0 if anchor[1] > c[1] else 2
  36. else:
  37. return 1 if anchor[0] < c[0] else 3
  38. def r_func(anchor, c, is_horizontal):
  39. if is_horizontal:
  40. return 0 if anchor[0] > c[0] else 2
  41. else:
  42. return 1 if anchor[1] > c[1] else 3
  43. self.direction_funcs = {
  44. Direction.TOP: t_func,
  45. Direction.LEFT: l_func,
  46. Direction.BOTTOM: b_func,
  47. Direction.RIGHT: r_func
  48. }
  49. # pic中心点
  50. def get_pic_center(self, res) -> Tuple[float, float]:
  51. boxs = []
  52. for row in res:
  53. for r in row:
  54. boxs.extend(r.box)
  55. boxs = np.stack(boxs)
  56. l, t = np.min(boxs, 0)
  57. r, b = np.max(boxs, 0)
  58. return (l + r) / 2, (t + b) / 2
  59. # 是否有锚点
  60. def is_anchor(self, txt, box):
  61. pass
  62. # 找锚点
  63. def find_anchor(self, res):
  64. for row in res:
  65. for r in row:
  66. if self.is_anchor(r.txt, r.box):
  67. # l, t = np.min(r.box, 0)
  68. # r, b = np.max(r.box, 0)
  69. # return True, (l + r) / 2, (t + b) / 2
  70. return True, r.center[0], r.center[1]
  71. return False, 0., 0.
  72. # get angle
  73. def locate_anchor(self, res, is_horizontal):
  74. found, a_cx, a_cy = self.find_anchor(res)
  75. cx, cy = self.get_pic_center(res)
  76. if found is False: raise Exception(f'识别不到anchor{self.name}')
  77. pre = None
  78. for d in self.direction:
  79. angle_func = self.direction_funcs.get(d, None)
  80. angle = angle_func((a_cx, a_cy), (cx, cy), is_horizontal)
  81. if pre is None:
  82. pre = angle
  83. else:
  84. if pre != angle:
  85. raise Exception('angle is not compatible')
  86. return pre
  87. # 子类1 户口本首页1
  88. class FrontAnchor(OcrAnchor):
  89. def __init__(self, name: str, d: List[Direction]):
  90. super(FrontAnchor, self).__init__(name, d)
  91. def is_anchor(self, txt, box):
  92. txts = re.findall('承办', txt)
  93. if len(txts) > 0:
  94. return True
  95. return False
  96. def locate_anchor(self, res, is_horizontal):
  97. return super(FrontAnchor, self).locate_anchor(res, is_horizontal)
  98. # 子类2 常驻人口页0
  99. class PeopleAnchor(OcrAnchor):
  100. def __init__(self, name: str, d: List[Direction]):
  101. super(PeopleAnchor, self).__init__(name, d)
  102. def is_anchor(self, txt, box):
  103. txts = re.findall('常住', txt) or re.findall('登记卡', txt)
  104. if len(txts) > 0:
  105. return True
  106. return False
  107. def locate_anchor(self, res, is_horizontal):
  108. return super(PeopleAnchor, self).locate_anchor(res, is_horizontal)
  109. # 调用以上 🔧工具
  110. # <- ocr_生数据
  111. # == ocr_熟数据(行处理后)
  112. # -> 角度0/1/2/3
  113. def detect_angle(result, ocr_anchor: OcrAnchor):
  114. lp = LineParser(result)
  115. res = lp.parse()
  116. print('------ angle ocr -------')
  117. print(res)
  118. print('------ angle ocr -------')
  119. is_horizontal = lp.is_horizontal
  120. return ocr_anchor.locate_anchor(res, is_horizontal)
  121. @dataclass
  122. class AngleDetector(object):
  123. """
  124. 角度检测器
  125. """
  126. ocr: PaddleOCR
  127. # 角度检测器
  128. # <- img(cv2格式) img_type
  129. # == result <- img(cv2)
  130. # -> angle result(ocr生)
  131. def detect_angle(self, img, image_type):
  132. image_type = int(image_type)
  133. ocr_anchor = PeopleAnchor('常住', [Direction.TOP]) if image_type == 0 else FrontAnchor('承办人', [Direction.BOTTOM,
  134. Direction.LEFT])
  135. result = self.ocr.ocr(img, cls=True)
  136. try:
  137. angle = detect_angle(result, ocr_anchor)
  138. return angle, result
  139. except Exception as e:
  140. print(e)
  141. # 如果第一次识别不到,旋转90度再识别
  142. img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
  143. result = self.ocr.ocr(img, cls=True)
  144. angle = detect_angle(result, ocr_anchor)
  145. # 旋转90度之后要重新计算角度
  146. return (angle - 1 + 4) % 4, result