1 項目介紹
項目架構如下:
- APP/WEB/?程序為OCR識別接?調?端,調?OCR接?,實現OCR功能。本項?我們只實現Android APP開發。
- Nginx反向代理和負載均衡功能,通過Nginx實現對外?暴露接?,對內負載均衡SpringBoot實現的OCR服務。
- OCR服務通過Springboot實現,主要功能是提供具體的OCR接?實現,其流程是調?內部PaddleOCR服務,解析和處理返回結果,最終返回結果給接?調?者。為了穩定性和安全性,添加了熔斷限流、Token認證功能。為了?便部署,會以Docker形式部署該服務。
- PaddleOCR是OCR識別的具體實現,會提供?個OCR識別接?,供內部調?。由于不同的部署?式(普通部署和paddleocr serving?式部署),PaddleOCR在普通部署?式下,?法利?CPU多核(Servering?式不存在該問題),因此會在同?個服務器部署多個實例,解決CPU利?率差以提升性能。為了?便PaddleOCR部署,會以Docker形式部署。后邊會講解普通?式部署和Servering?式部署,如何構建docker鏡像及部署流程。
2 python開發PaddleOCR內部接口
2.1 安裝 Flask
pip install flask==3.0.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
2.2 編寫簡單Flask接口進行測試
新建python文件,編寫接口如下:
@app.route("/learn/hello")
def hello_world():return "Hello,World!"
結果如下:
接口代碼如下:
@app.route("/learn/path/<string:name>")
def learn_path(name):return name
結果如下:
接口代碼如下:
@app.route("/learn/m-get", methods=["GET"])
def learn_get_method():age = request.args.get("age")name = request.args.get("name")logging.info("learn m-get age 是:%s, name是:%s", age, name)return "SUCCESS", 200
結果如下:
接口代碼如下:
# 通過POST方式獲取參數,參數時jsOn符中
@app.route("/learn/m-post", methods=["POST"])
def learn_post_method():data = request.datalogging.info("learn post-m data :%s", data)data = json.loads(data)age = data["age"]name = data["name"]logging.info("learn post-m age:%s name:%s", age, name)return jsonify(data), 200
結果如下:
上面都成功說明Flask沒問題。
完整代碼如下:
import json
import logging
from flask import Flask, request, jsonifydef init_log():# 設置打印到控制臺的格式和等級logging.basicConfig(format='%(asctime)s %(filename)s %(levelname)s %(message)s', datefmt='%a %d %b %Y %H:%M:%S',level=logging.INFO)# 設置輸出到的文件和編碼file_handler = logging.FileHandler("ocr.log", encoding="utf-8")# 設置輸出等級file_handler.setLevel(logging.INFO)# 設置輸出到文件的日志格式file_handler.setFormatter(logging.Formatter('%(asctime)s %(filename)s %(levelname)s %(message)s'))logger = logging.getLogger()logger.handlers.append(file_handler)init_log()# name是python中的特殊變量,如果文件作為主程序執行(例如直接技行),那么..name.的值就是_main_-,如果是被其它模塊引入,那么__name-就是模塊名稱
app = Flask(__name__)@app.route("/learn/hello")
def hello_world():return "Hello,World!"@app.route("/learn/path/<string:name>")
def learn_path(name):return name@app.route("/learn/m-get", methods=["GET"])
def learn_get_method():age = request.args.get("age")name = request.args.get("name")logging.info("learn m-get age 是:%s, name是:%s", age, name)return "SUCCESS", 200# 通過POST方式獲取參數,參數時jsOn符中
@app.route("/learn/m-post", methods=["POST"])
def learn_post_method():data = request.datalogging.info("learn post-m data :%s", data)data = json.loads(data)age = data["age"]name = data["name"]logging.info("learn post-m age:%s name:%s", age, name)return jsonify(data), 200if __name__ == '__main__':# 接收所有的IP請求,debug=True表示代列修改web容器公業啟app.run(host='0.0.0.0', debug=True, port=8888)
2.3 Flask集成PaddleOCR
檢測+?向分類器+識別全流程,只需要下?三?代碼
#導?依賴
from paddleocr import PaddleOCR
#創建PaddleOCR對象,只需要在初始化時執??次該語句
ocr = PaddleOCR(use_angle_cls=True, det=False, use_gpu=False)
#識別圖?返回結果,cls=True 表示識別旋轉180度的?字,如果沒有?字旋轉180度,那么
#可以cls=False,這樣會提升性能,旋轉90度和270度也能夠識別
result = ocr.ocr(imgPath, cls=True)
完整的PaddleOCR內部接口開發如下:
下?這段python代碼主要是實現:通過flask創建web容器,并通過/ocr 接?調? paddleocr進?圖?識別,并通過json格式返回識別結果。
import json
import logging
from flask import Flask, request, jsonify
from paddleocr import PaddleOCRdef init_log():# 設置打印到控制臺的格式和等級logging.basicConfig(format='%(asctime)s %(filename)s %(levelname)s %(message)s', datefmt='%a %d %b %Y %H:%M:%S',level=logging.INFO)# 設置輸出到的文件和編碼file_handler = logging.FileHandler("ocr.log", encoding="utf-8")# 設置輸出等級file_handler.setLevel(logging.INFO)# 設置輸出到文件的日志格式file_handler.setFormatter(logging.Formatter('%(asctime)s %(filename)s %(levelname)s %(message)s'))logger = logging.getLogger()logger.handlers.append(file_handler)init_log()# name 是python中的特殊變量,如果文件作為主程序執行(例如直接執行),那么__name__的值就是__main__,如果是被其它模塊引入,那么__name__就是模塊名稱
app = Flask(__name__)# 創建一個PaddleOCR對象,使用方向識別器,不使用gpu進行技術,通過cpu進行計算。PaddleOCR我們只需要初始化一次,會將模型加載到內存,會將相關模型下載如果是第一次使用
ocr = PaddleOCR(usr_angle_cls=True, use_gpu=False)# 通過POST方法識別圖片,傳入參數為圖片的路徑
@app.route("/ocr", methods=["POST"])
def learn_post_method():try:data = json.loads(request.data)img_path = data["imgPath"]logging.info("ocr imgPath : %s", img_path)ocr_result = ocr.ocr(img_path)return jsonify({"code": 0, "msg": "ok", "data": ocr_result}), 200except Exception as e:logging.error("ocr error: %s", str(e))ocr_result = {"code": -1, "msg": str(e)}return jsonify(ocr_result), 200if __name__ == '__main__':# 可以返回中文字符app.config['JSON_AS_ASCII'] = False# 接收所有的IP請求,debug=True表示代碼修改web容器會重啟app.run(host='0.0.0.0', debug=True, port=8888)
- import 表示導?整個module(模塊),?個.py?件就是?個module
- from A import B 表示導?A模塊中的B(可以為?法、類)
- flask是python實現的web框架,類似Tomcat
- 如果是json格式的請求數據,則是采?request.data來獲取請求體的字符串。
- 如果是form表單的請求體,那么則可以使?request.form來獲取參數。
- 如果是url參數,例如:url?param1=xx?m2=xx,那么則可以使?request.args來獲取參數。
- 如果需要區分GET\POST請求?法,則可以使?request.method來進?判斷區分
- 參考:https://cloud.tencent.com/developer/article/1539199,解釋的很清楚
- @app.route 聲明?個接?,指定請求?法和U請求路徑
- 作為 Python 的內置變量,__name__它是每個 Python 模塊必備的屬性,但它的值取決于你是如何執?這段代碼。通過__name__變量,可以判斷出這時代碼是被直接運?,還是被導?到其他程序中去了。當直接執??段腳本的時候,這段腳本的 __name__變量等于 '__main__',當這段腳本被導?其他程序的時候,__name__ 變量等于腳本本身的名字。
接口測試,如下:
結果如下:
{"code": 0,"data": [[[[[1.0,12.0],[222.0,12.0],[222.0,35.0],[1.0,35.0]],["2.安裝tesseract-ocr",0.9961034059524536]],[[[4.0,55.0],[384.0,54.0],[384.0,72.0],[4.0,73.0]],["OCR(OpticalCharacterRecognition,光學字符識別)軟件",0.9673566222190857]],[[[1.0,88.0],[382.0,87.0],[382.0,103.0],[1.0,104.0]],["安裝包含兩個部分:ORC引擎本身以及對應語言的訓練數據",0.9957185387611389]],[[[0.0,155.0],[389.0,153.0],[389.0,172.0],[0.0,174.0]],["githubttt址:https://github.com/tesseract-ocr/tesseract",0.9804431200027466]],[[[0.0,186.0],[576.0,187.0],[576.0,207.0],[0.0,206.0]],["You can either Install Tesseract via pre-built binary package or build it from source.",0.9568857550621033]],[[[1.0,221.0],[86.0,224.0],[85.0,241.0],[1.0,239.0]],["windows:",0.9869498014450073]],[[[1.0,256.0],[915.0,258.0],[915.0,278.0],[1.0,276.0]],["The latest installer can be downloaded here: tesseract-ocr-setup-3.05.01.exe and tesseract-ocr-setup-4.00.00dev.exe (experimental).",0.9753488898277283]]]],"msg": "ok"
}