anchor.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import re
  2. from dataclasses import dataclass
  3. from enum import Enum
  4. from typing import Tuple, List
  5. import cv2
  6. import numpy as np
  7. from paddleocr import PaddleOCR
  8. from core.line_parser import LineParser
  9. class Direction(Enum):
  10. TOP = 0
  11. RIGHT = 1
  12. BOTTOM = 2
  13. LEFT = 3
  14. class OcrAnchor(object):
  15. def __init__(self, name: str, d: List[Direction]):
  16. self.name = name
  17. self.direction = d
  18. def t_func(anchor, c, is_horizontal):
  19. if is_horizontal:
  20. return 0 if anchor[1] < c[1] else 2
  21. else:
  22. return 1 if anchor[0] > c[0] else 3
  23. def l_func(anchor, c, is_horizontal):
  24. if is_horizontal:
  25. return 0 if anchor[0] < c[0] else 2
  26. else:
  27. return 1 if anchor[1] < c[1] else 3
  28. def b_func(anchor, c, is_horizontal):
  29. if is_horizontal:
  30. return 0 if anchor[1] > c[1] else 2
  31. else:
  32. return 1 if anchor[0] < c[0] else 3
  33. def r_func(anchor, c, is_horizontal):
  34. if is_horizontal:
  35. return 0 if anchor[0] > c[0] else 2
  36. else:
  37. return 1 if anchor[1] > c[1] else 3
  38. self.direction_funcs = {
  39. Direction.TOP: t_func,
  40. Direction.BOTTOM: b_func,
  41. Direction.LEFT: l_func,
  42. Direction.RIGHT: r_func,
  43. }
  44. # 获取中心区域坐标 -> (x, y)
  45. def get_rec_area(self, res) -> Tuple[float, float]:
  46. """获得整张身份证的识别区域, 返回识别区域的中心点"""
  47. boxes = []
  48. for row in res:
  49. for r in row:
  50. boxes.extend(r.box)
  51. boxes = np.stack(boxes)
  52. l, t = np.min(boxes, 0)
  53. r, b = np.max(boxes, 0)
  54. return (l + r) / 2, (t + b) / 2
  55. # 判断是否是 锚点
  56. def is_anchor(self, txt, box, conf) -> bool:
  57. pass
  58. # 寻找锚点
  59. def find_anchor(self, res) -> Tuple[bool, float, float]:
  60. """
  61. 寻找锚点 中心点坐标
  62. """
  63. for row in res:
  64. for r in row:
  65. txt = r.txt.replace('-', '').replace(' ', '')
  66. box = r.box
  67. conf = r.conf
  68. flag = self.is_anchor(txt, box, conf)
  69. if flag:
  70. l, t = np.min(box, 0)
  71. r, b = np.max(box, 0)
  72. return True, (l + r) / 2, (t + b) / 2
  73. return False, 0., 0.
  74. # 定位 锚点 -> 角度
  75. # -> 锚点(x, y) pic(x, y) is_horizontal
  76. def locate_anchor(self, res, is_horizontal) -> int:
  77. found, id_cx, id_cy = self.find_anchor(res)
  78. # 如果识别不到身份证号
  79. if not found: raise Exception(f'识别不到anchor{self.name}')
  80. cx, cy = self.get_rec_area(res)
  81. pre = None
  82. for d in self.direction:
  83. f = self.direction_funcs.get(d, None)
  84. angle = f((id_cx, id_cy), (cx, cy), is_horizontal)
  85. if pre is None:
  86. pre = angle
  87. else:
  88. if angle != pre:
  89. raise Exception('angle is not compatiable')
  90. return pre
  91. class BankCardAnchor(OcrAnchor):
  92. def __init__(self, name: str, d: List[Direction]):
  93. super(BankCardAnchor, self).__init__(name, d)
  94. def is_anchor(self, txt, box, conf) -> bool:
  95. if len(re.findall('\d{16,20}', txt)) > 0 and conf > 0.95:
  96. return True
  97. elif len(re.findall('\d{10,16}', txt)) > 0 and conf > 0.95:
  98. return True
  99. elif len(re.findall('\d{6,10}', txt)) > 0 and conf > 0.95:
  100. return True
  101. elif len(re.findall('\d{4,6}', txt)) > 0 and conf > 0.95:
  102. return True
  103. elif conf > 0.95:
  104. return True
  105. return False
  106. def locate_anchor(self, res, is_horizontal) -> int:
  107. return super(BankCardAnchor, self).locate_anchor(res, is_horizontal)