|
@@ -1,90 +1,160 @@
|
|
|
-import dataclasses
|
|
|
+import re
|
|
|
+from dataclasses import dataclass
|
|
|
|
|
|
import cv2
|
|
|
import numpy as np
|
|
|
-
|
|
|
-from dataclasses import dataclass
|
|
|
from paddleocr import PaddleOCR
|
|
|
|
|
|
+from core.line_parser import LineParser
|
|
|
+
|
|
|
+
|
|
|
+def get_rec_area(res):
|
|
|
+ """获得整张身份证的识别区域, 返回识别区域的中心点"""
|
|
|
+ boxes = []
|
|
|
+ for row in res:
|
|
|
+ for r in row:
|
|
|
+ boxes.extend(r.box)
|
|
|
+ boxes = np.stack(boxes)
|
|
|
+ l, t = np.min(boxes, 0)
|
|
|
+ r, b = np.max(boxes, 0)
|
|
|
+ # 识别区域的box
|
|
|
+ big_box = [[l, t], [r, t], [r, b], [l, b]]
|
|
|
+ w, h = (r - l, b - t)
|
|
|
+ return (l + r) / 2, (t + b) / 2, big_box
|
|
|
+
|
|
|
+
|
|
|
+def find_idno(res):
|
|
|
+ """寻找身份证号的识别区域以及中心点,根据身份证的w > h判断是否水平"""
|
|
|
+ for row in res:
|
|
|
+ for r in row:
|
|
|
+ txt = r.txt.replace('-', '').replace(' ', '')
|
|
|
+ box = r.box
|
|
|
+ txts = re.findall('\d{10,18}', txt)
|
|
|
+ if len(txts) > 0:
|
|
|
+ l, t = np.min(box, 0)
|
|
|
+ r, b = np.max(box, 0)
|
|
|
+ return txts[0], (l + r) / 2, (t + b) / 2, (r - l) > (b - t), box
|
|
|
+ return '', 0, 0, True, []
|
|
|
+
|
|
|
+
|
|
|
+def detect_angle(result):
|
|
|
+ lp = LineParser(result)
|
|
|
+ res = lp.parse()
|
|
|
+ idno, id_cx, id_cy, is_horizon, id_box = find_idno(res)
|
|
|
+ # 如果识别不到身份证号
|
|
|
+ if not idno: raise Exception('识别不到身份证号')
|
|
|
+ cx, cy, big_box = get_rec_area(res)
|
|
|
+ # print(f'id_cx: {id_cx}, id_cy: {id_cy}')
|
|
|
+ # print(f'cx: {cx}, cy: {cy}')
|
|
|
+
|
|
|
+ if is_horizon:
|
|
|
+ # 如果是水平的,身份证号的位置在相对识别区域的下方,方向则为0度,否则是180度
|
|
|
+ return 0 if id_cy > cy else 2
|
|
|
+ else:
|
|
|
+ # 如果是竖直的,身份证号的相对位置如果在左边,方向为90度,否则270度
|
|
|
+ return 1 if id_cx < cx else 3
|
|
|
+
|
|
|
|
|
|
@dataclass
|
|
|
# 角度检测器
|
|
|
class AngleDetector(object):
|
|
|
ocr: PaddleOCR
|
|
|
|
|
|
- def detect_angle(self, img, result) -> int:
|
|
|
- wc = 0
|
|
|
- hc = 0
|
|
|
- count_0 = 0
|
|
|
- count_180 = 0
|
|
|
- angle = 0
|
|
|
+ def detect_angle(self, img, image_type):
|
|
|
+ image_type = int(image_type)
|
|
|
+ if image_type != 0:
|
|
|
+ return self._detect_back(img)
|
|
|
+
|
|
|
+ return self._detect_front(img)
|
|
|
+
|
|
|
+ def _detect_front(self, img):
|
|
|
+ result = self.ocr.ocr(img, cls=True)
|
|
|
+
|
|
|
+ print('------ angle ocr -------')
|
|
|
print(result)
|
|
|
- for res in result:
|
|
|
- txt = res[1][0]
|
|
|
- if '号' not in txt: continue
|
|
|
- a = np.array(res[0])
|
|
|
- l, t = np.min(a, axis=0).tolist()
|
|
|
- r, b = np.max(a, axis=0).tolist()
|
|
|
- l, t, r, b = list(map(int, [l, t, r, b]))
|
|
|
- if b - t > r - l:
|
|
|
- hc += 1
|
|
|
- else:
|
|
|
- wc += 1
|
|
|
- imgb = img[t:b, l:r, :]
|
|
|
- r = self.ocr.ocr(imgb, det=False, rec=False, cls=True)
|
|
|
- print(f'ocr angle: {r}')
|
|
|
- if int(r[0][0]) == 180:
|
|
|
- count_180 += 1
|
|
|
- else:
|
|
|
- count_0 += 1
|
|
|
- if hc >= wc:
|
|
|
- if count_0 >= count_180:
|
|
|
- angle = 90
|
|
|
- else:
|
|
|
- angle = 270
|
|
|
+ print('------ angle ocr -------')
|
|
|
+
|
|
|
+ try:
|
|
|
+ return detect_angle(result), result
|
|
|
+ except Exception as e:
|
|
|
+ print(e)
|
|
|
+ img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
|
|
|
+ result = self.ocr.ocr(img, cls=True)
|
|
|
+ angle = detect_angle(result)
|
|
|
+ return (angle-1+4)/4, result
|
|
|
+
|
|
|
+ def _detect_back(self, image):
|
|
|
+ mask = np.zeros(image.shape, dtype=np.uint8)
|
|
|
+ gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
|
|
|
+ blur = cv2.GaussianBlur(gray, (3, 3), 0)
|
|
|
+ adaptive = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 15, 4)
|
|
|
+
|
|
|
+ cnts = cv2.findContours(adaptive, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
|
|
|
+ cnts = cnts[0] if len(cnts) == 2 else cnts[1]
|
|
|
+
|
|
|
+ for c in cnts:
|
|
|
+ area = cv2.contourArea(c)
|
|
|
+ if area < 45000 and area > 20:
|
|
|
+ cv2.drawContours(mask, [c], -1, (255, 255, 255), -1)
|
|
|
+
|
|
|
+ mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
|
|
|
+ h, w = mask.shape
|
|
|
+
|
|
|
+ # Horizontal
|
|
|
+ if w > h:
|
|
|
+ left = mask[0:h, 0:0 + w // 2]
|
|
|
+ right = mask[0:h, w // 2:]
|
|
|
+ left_pixels = cv2.countNonZero(left)
|
|
|
+ right_pixels = cv2.countNonZero(right)
|
|
|
+ print(f'left: {left_pixels}, right: {right_pixels}')
|
|
|
+ angle = 0 if left_pixels >= right_pixels else 2
|
|
|
+ # Vertical
|
|
|
else:
|
|
|
- if count_0 > count_180:
|
|
|
- angle = 0
|
|
|
- else:
|
|
|
- angle = 180
|
|
|
-
|
|
|
- return angle
|
|
|
-
|
|
|
-
|
|
|
-def detect_angle(image):
|
|
|
- mask = np.zeros(image.shape, dtype=np.uint8)
|
|
|
- gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
|
|
|
- blur = cv2.GaussianBlur(gray, (3, 3), 0)
|
|
|
- adaptive = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 15, 4)
|
|
|
-
|
|
|
- cnts = cv2.findContours(adaptive, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
|
|
|
- cnts = cnts[0] if len(cnts) == 2 else cnts[1]
|
|
|
-
|
|
|
- for c in cnts:
|
|
|
- area = cv2.contourArea(c)
|
|
|
- if area < 45000 and area > 20:
|
|
|
- cv2.drawContours(mask, [c], -1, (255, 255, 255), -1)
|
|
|
-
|
|
|
- mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
|
|
|
- h, w = mask.shape
|
|
|
-
|
|
|
- # Horizontal
|
|
|
- if w > h:
|
|
|
- left = mask[0:h, 0:0 + w // 2]
|
|
|
- right = mask[0:h, w // 2:]
|
|
|
- left_pixels = cv2.countNonZero(left)
|
|
|
- right_pixels = cv2.countNonZero(right)
|
|
|
- return 0 if left_pixels >= right_pixels else 180
|
|
|
- # Vertical
|
|
|
- else:
|
|
|
- top = mask[0:h // 2, 0:w]
|
|
|
- bottom = mask[h // 2:, 0:w]
|
|
|
- top_pixels = cv2.countNonZero(top)
|
|
|
- bottom_pixels = cv2.countNonZero(bottom)
|
|
|
- return 90 if bottom_pixels >= top_pixels else 270
|
|
|
+ top = mask[0:h // 2, 0:w]
|
|
|
+ bottom = mask[h // 2:, 0:w]
|
|
|
+ top_pixels = cv2.countNonZero(top)
|
|
|
+ bottom_pixels = cv2.countNonZero(bottom)
|
|
|
+ print(f'top: {top_pixels}, bottom: {bottom_pixels}')
|
|
|
+ angle = 1 if bottom_pixels <= top_pixels else 3
|
|
|
+ return angle, None
|
|
|
|
|
|
|
|
|
-if __name__ == '__main__':
|
|
|
- image = cv2.imread('d40.jpg')
|
|
|
- angle = detect_angle(image)
|
|
|
- print(angle)
|
|
|
+#
|
|
|
+#
|
|
|
+# def detect_angle(image):
|
|
|
+# mask = np.zeros(image.shape, dtype=np.uint8)
|
|
|
+# gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
|
|
|
+# blur = cv2.GaussianBlur(gray, (3, 3), 0)
|
|
|
+# adaptive = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 15, 4)
|
|
|
+#
|
|
|
+# cnts = cv2.findContours(adaptive, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
|
|
|
+# cnts = cnts[0] if len(cnts) == 2 else cnts[1]
|
|
|
+#
|
|
|
+# for c in cnts:
|
|
|
+# area = cv2.contourArea(c)
|
|
|
+# if area < 45000 and area > 20:
|
|
|
+# cv2.drawContours(mask, [c], -1, (255, 255, 255), -1)
|
|
|
+#
|
|
|
+# mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
|
|
|
+# h, w = mask.shape
|
|
|
+#
|
|
|
+# # Horizontal
|
|
|
+# if w > h:
|
|
|
+# left = mask[0:h, 0:0 + w // 2]
|
|
|
+# right = mask[0:h, w // 2:]
|
|
|
+# left_pixels = cv2.countNonZero(left)
|
|
|
+# right_pixels = cv2.countNonZero(right)
|
|
|
+# return 0 if left_pixels >= right_pixels else 180
|
|
|
+# # Vertical
|
|
|
+# else:
|
|
|
+# top = mask[0:h // 2, 0:w]
|
|
|
+# bottom = mask[h // 2:, 0:w]
|
|
|
+# top_pixels = cv2.countNonZero(top)
|
|
|
+# bottom_pixels = cv2.countNonZero(bottom)
|
|
|
+# return 90 if bottom_pixels >= top_pixels else 270
|
|
|
+#
|
|
|
+#
|
|
|
+# if __name__ == '__main__':
|
|
|
+# image = cv2.imread('d40.jpg')
|
|
|
+# angle = detect_angle(image)
|
|
|
+# print(angle)
|