Forráskód Böngészése

v3.7: 支持银行卡卡号识别

Tinger 2 éve
szülő
commit
fca9d67d6a
8 módosított fájl, 138 hozzáadás és 8 törlés
  1. 2 1
      app.py
  2. 1 0
      blues/__init__.py
  3. 95 0
      blues/bank.py
  4. 2 2
      blues/idc.py
  5. 4 0
      static/html/bank.svg
  6. 19 0
      templates/bank_index.html
  7. 6 2
      templates/navigate.html
  8. 9 3
      utils/util.py

+ 2 - 1
app.py

@@ -1,6 +1,6 @@
 from utils import conf
-from blues import com, idc
 from flask_cors import CORS
+from blues import com, idc, bank
 from flask import Flask, render_template, Response
 
 
@@ -11,6 +11,7 @@ def init() -> "Flask":
 
     this.register_blueprint(com)
     this.register_blueprint(idc)
+    this.register_blueprint(bank)
 
     return this
 

+ 1 - 0
blues/__init__.py

@@ -1,2 +1,3 @@
 from .com import com
 from .idc import idc
+from .bank import bank

+ 95 - 0
blues/bank.py

@@ -0,0 +1,95 @@
+import re
+from time import time
+from utils.util import *
+from utils.conf import MAX_CONTENT_LENGTH
+from flask import Blueprint, views, render_template, request
+from utils.logger import Logger
+
+bank = Blueprint("bank", __name__, url_prefix="/bank")
+
+_NumberPtn = re.compile(r"(?P<number>\d{16,19})")
+
+
+class BankView(views.MethodView):
+    @staticmethod
+    def get():
+        return render_template("bank_index.html")
+
+    @staticmethod
+    def post():
+        start = time()
+        pic = request.files.get("picture")
+        if pic is None:
+            return Response("empty body")
+        ext = get_ext_name(pic.filename)
+        if not is_image_ext(ext):
+            return Response("文件类型错误")
+        content = pic.read()
+        if len(content) > MAX_CONTENT_LENGTH:
+            return Response("文件过大,请重新选择")
+
+        img = read_img(content)
+        cropped = crop_img(img)  # 边缘裁剪,对深色背景的效果很好
+        images = rot_img_2(cropped)
+        recognizes = Engine.rec_multi(images)
+        info, sta, idx = {}, False, 0
+        for i, ocr_res in enumerate(recognizes):
+            rec_str = "".join([it[0] for it in ocr_res])
+            if search := _NumberPtn.search(rec_str):
+                sta, idx = True, i
+                info["number"] = search.group("number")
+                break
+            else:
+                Logger.error(rec_str)
+        info["duration"] = time() - start
+        if sta:
+            raw_path = f"static/images/{current_time()}_{rand_str()}.{ext}"
+            save_img(raw_path, images[idx])
+            return Response(data=info)
+        return Response("识别失败,请重新选择", info)
+
+
+class BankHtmlView(views.MethodView):
+    @staticmethod
+    def post():
+        start = time()
+        pic = request.files.get("picture")
+        if pic is None:
+            return Response("empty body")
+        ext = get_ext_name(pic.filename)
+        if not is_image_ext(ext):
+            return Response("文件类型错误")
+        content = pic.read()
+        if len(content) > MAX_CONTENT_LENGTH:
+            return Response("文件过大,请重新选择")
+
+        img = read_img(content)
+        cropped = crop_img(img)
+        images = rot_img_2(cropped)
+        recognizes = Engine.rec_multi(images)
+        info, err_rec, sta, idx = {}, [], False, 0
+        msg = "识别失败,请重新选择"
+        for i, ocr_res in enumerate(recognizes):
+            rec_str = "".join([it[0] for it in ocr_res])
+            if search := _NumberPtn.search(rec_str):
+                sta, idx = True, i
+                info["number"] = search.group("number")
+                msg = "识别成功"
+                break
+            else:
+                Logger.error(rec_str)
+                err_rec.append(rec_str)
+
+        file_path = f"static/images/{current_time()}_{rand_str()}.{ext}"
+        save_img(file_path, images[idx])
+
+        info["SUCCESS"] = str(sta).upper()
+        info["MESSAGE"] = msg
+        if len(err_rec):
+            info["MESSAGE"] += "<br>识别结果:<br>" + "<br>".join(err_rec)
+        info["DURATION"] = time() - start  # noqa
+        return render_template("k-v_result.html", raw=file_path, data=info)
+
+
+bank.add_url_rule("/", view_func=BankView.as_view("bank"))
+bank.add_url_rule("/html/", view_func=BankHtmlView.as_view("bank-html"))

+ 2 - 2
blues/idc.py

@@ -88,7 +88,7 @@ class IdcView(views.MethodView):
 
         img = read_img(content)
         cropped = crop_img(img)  # 边缘裁剪,对深色背景的效果很好
-        images = [item for item in rot_img(cropped) if item.shape[0] < item.shape[1]]  # 旋转后仅取横长竖宽
+        images = rot_img_2(cropped)
         recognizes = Engine.rec_multi(images)
         info, msg, sta, idx = {}, "识别失败,请重新选择", False, 0
         for i, ocr_res in enumerate(recognizes):
@@ -133,7 +133,7 @@ class IdcHtmlView(views.MethodView):
 
         img = read_img(content)
         cropped = crop_img(img)
-        images = [item for item in rot_img(cropped) if item.shape[0] < item.shape[1]]
+        images = rot_img_2(cropped)
         recognizes = Engine.rec_multi(images)
         info, err_rec, sta, idx = {}, [], False, 0
         msg = "识别失败,请重新选择"

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 4 - 0
static/html/bank.svg


+ 19 - 0
templates/bank_index.html

@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="zh">
+<head>
+    <meta charset="UTF-8">
+    <title>upload index</title>
+</head>
+<body>
+<h2>API 银行卡:</h2>
+<form action="/bank/" method="POST" enctype="multipart/form-data">
+    <input type="file" name="picture">
+    <input type="submit" value="上传并识别">
+</form>
+<h2>在线 银行卡:</h2>
+<form action="/bank/html/" method="POST" enctype="multipart/form-data">
+    <input type="file" name="picture">
+    <input type="submit" value="上传并识别">
+</form>
+</body>
+</html>

+ 6 - 2
templates/navigate.html

@@ -54,14 +54,18 @@
 <body>
 <h1>HuiMv OCR Navigator</h1>
 <div class="demos">
-    <div rel="/com" class="demo link">
+    <div rel="/com/" class="demo link">
         <img src="/static/html/common.svg" alt="common">
         <span>通用内容识别模型,可识别任意图片中的所有文字内容,对图片要求不高。</span>
     </div>
-    <div rel="/idc" class="demo link">
+    <div rel="/idc/" class="demo link">
         <img src="/static/html/identity.svg" alt="identity">
         <span>中国大陆身份证内容识别,主要识别:姓名、性别、民族、身份证号、地址、有效日期。</span>
     </div>
+    <div rel="/bank/" class="demo link">
+        <img src="/static/html/bank.svg" alt="bank">
+        <span>主流银行卡卡号识别,卡号为16-19位数字</span>
+    </div>
     <div class="demo">
         <img src="/static/html/more.svg" alt="more">
         <span>更多内容,有待开发...<br>更多内容,有待开发...<br>更多内容,有待开发...</span>

+ 9 - 3
utils/util.py

@@ -10,8 +10,8 @@ from time import localtime, strftime
 
 __all__ = [
     "Response", "rand_str", "current_time", "get_ext_name", "is_image_ext",
-    "str_include", "read_img", "compress_img", "crop_img", "rot_img", "save_img",
-    "Engine"
+    "str_include", "read_img", "compress_img", "crop_img", "rot_img_2", "rot_img_4",
+    "save_img", "Engine"
 ]
 
 __StrBase = "qwertyuioplkjhgfdsazxcvbnm1234567890ZXCVBNMLKJHGFDSAQWERTYUIOP"
@@ -93,7 +93,13 @@ def crop_img(image: "np.ndarray") -> "np.ndarray":
     return image[min(box[:, 1]):max(box[:, 1]), min(box[:, 0]):max(box[:, 0])]
 
 
-def rot_img(img: "np.ndarray") -> "list[np.ndarray]":
+def rot_img_2(img: "np.ndarray") -> "list[np.ndarray]":
+    if img.shape[0] > img.shape[1]:  # 0: height, 1: width
+        return [np.rot90(img), np.rot90(img, 3)]
+    return [img, np.rot90(img, 2)]
+
+
+def rot_img_4(img: "np.ndarray") -> "list[np.ndarray]":
     return [img, np.rot90(img), np.rot90(img, 2), np.rot90(img, 3)]