PaddleOCR 安装与实践(CPU版)

0、glibc升级至2.23以及python升级至3.7

https://blog.csdn.net/qq_20989105/article/details/90712139   # glibc 2.23升级
https://www.cnblogs.com/goldsunshine/p/12938654.html # python3.7 升级

1、安装(请按照官网的安装,本人使用docker方式,也是推荐方式,至于克隆源码,我用的是gitee中的,汗......github太慢了.....)

https://hub.fastgit.org/PaddlePaddle/PaddleOCR/blob/release/2.1/doc/doc_ch/installation.md

2、测试是否安装成功,标红说明安装成功啦!

λ ywj-computer /home/PaddleOCR/tools {release/2.0} python3
Python 3.7.0 (default, Apr 13 2021, 06:08:34) 
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import paddle
grep: warning: GREP_OPTIONS is deprecated; please use an alias or script
>>> 

3、测试官网例子玩玩,(标红的地方可以自己上传自己的图片,更换文件名即可)

python3 tools/infer/predict_system.py --image_dir="./doc/imgs/11.jpg" --det_model_dir="./inference/ch_ppocr_mobile_v2.0_det_infer/"  --rec_model_dir="./inference/ch_ppocr_mobile_v2.0_rec_infer/" --cls_model_dir="./inference/ch_ppocr_mobile_v2.0_cls_infer/" --use_angle_cls=True --use_space_char=True


python3 tools/infer/predict_system.py --image_dir="./doc/imgs/" --det_model_dir="./inference/ch_ppocr_mobile_v2.0_det_infer/"  --rec_model_dir="./inference/ch_ppocr_mobile_v2.0_rec_infer/" --cls_model_dir="./inference/ch_ppocr_mobile_v2.0_cls_infer/" --use_angle_cls=True --use_space_char=True


python3 tools/infer/predict_system.py --image_dir="./doc/imgs/3.jpg" --det_model_dir="./inference/ch_ppocr_mobile_v2.0_det_infer/"  --rec_model_dir="./inference/ch_ppocr_mobile_v2.0_rec_infer/" --cls_model_dir="./inference/ch_ppocr_mobile_v2.0_cls_infer/" --use_angle_cls=True --use_space_char=True --use_gpu=False
[2021/04/13 07:12:57] root INFO: dt_boxes num : 17, elapse : 0.9136314392089844
[2021/04/13 07:12:57] root INFO: cls num  : 17, elapse : 0.08672833442687988
[2021/04/13 07:12:58] root INFO: rec_res num  : 17, elapse : 0.17425131797790527
[2021/04/13 07:12:58] root INFO: Predict time of ./doc/imgs/4.jpg: 1.227s
[2021/04/13 07:12:58] root INFO: 性出住, 0.932
[2021/04/13 07:12:58] root INFO: 公民身份号码, 0.999
[2021/04/13 07:12:58] root INFO: 名, 1.000
[2021/04/13 07:12:58] root INFO: 男, 0.812
[2021/04/13 07:12:58] root INFO: 1991年7月7日, 0.998
[2021/04/13 07:12:58] root INFO: 杨深度, 0.990
[2021/04/13 07:12:58] root INFO: 村XXX, 0.999
[2021/04/13 07:12:58] root INFO: 湖南省XXXXXX, 0.991
[2021/04/13 07:12:58] root INFO: 民族汉, 0.924
[2021/04/13 07:12:58] root INFO: 43052XXXXXXXXXXX, 0.995
[2021/04/13 07:12:58] root INFO: The visualized image saved in ./inference_results/4.jpg

识别十分准确,只是要获取自己想要的格式以及信息提取还要优化很多

======================安装完成,部署测试==============================

1、部署有两种方式,我这边使用的是hub方式

部署安装文档说明:https://hub.fastgit.org/PaddlePaddle/PaddleOCR/tree/release/2.1/deploy/hubserving

2、返回需要的text字段

1、cd /home/PaddleOCR/deploy/hubserving/ocr_system

2、修改module.py文件:
    for dno in range(dt_num):
                text, score = rec_res[dno]
                rec_res_final.append({
                    'text': text
                  #  'confidence': float(score),
                  #  'text_region': dt_boxes[dno].astype(np.int).tolist()
                })
            all_results.append(rec_res_final)
3、可以看上面的注释部分是我们不需要的,我们只需要text部分

3、参数调节params.py(这里我没有做调整)

4、使用flask部署web框架

1、安装flask 
    pip3 install flask 
    pip3 install flask-cors
2、mv test_hubserving.py test_myocr.py,整体代码如下:
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
__dir__ = os.path.dirname(os.path.abspath(__file__))
sys.path.append(__dir__)
sys.path.append(os.path.abspath(os.path.join(__dir__, '..')))

from ppocr.utils.logging import get_logger
logger = get_logger()

import cv2
import numpy as np
import time
from PIL import Image
from ppocr.utils.utility import get_image_file_list
from tools.infer.utility import draw_ocr, draw_boxes

import requests
import json
import base64

from flask import Flask,request
from flask_cors import CORS


import requests
app = Flask(__name__)
CORS(app)  # 解决跨域问题

def cv2_to_base64(image):
    return base64.b64encode(image).decode('utf8')


def draw_server_result(image_file, res):
    img = cv2.imread(image_file)
    image = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    if len(res) == 0:
        return np.array(image)
    keys = res[0].keys()
    if 'text_region' not in keys:  # for ocr_rec, draw function is invalid 
        logger.info("draw function is invalid for ocr_rec!")
        return None
    elif 'text' not in keys:  # for ocr_det
        logger.info("draw text boxes only!")
        boxes = []
        for dno in range(len(res)):
            boxes.append(res[dno]['text_region'])
        boxes = np.array(boxes)
        draw_img = draw_boxes(image, boxes)
        return draw_img
    else:  # for ocr_system
        logger.info("draw boxes and texts!")
        boxes = []
        texts = []
        scores = []
        for dno in range(len(res)):
            boxes.append(res[dno]['text_region'])
            texts.append(res[dno]['text'])
            scores.append(res[dno]['confidence'])
        boxes = np.array(boxes)
        scores = np.array(scores)
        draw_img = draw_ocr(
            image, boxes, texts, scores, draw_txt=True, drop_score=0.5)
        return draw_img

@app.route("/test")
def test():
    return 'Hello World!'

@app.route("/myocr", methods=["POST"] )
def myocr():
    # 输入参数
    image_file = request.files['file']
    basepath = os.path.dirname(__file__)

    logger.info("{} basepath".format(basepath))

    savepath = os.path.join(basepath, image_file.filename)
    image_file.save(savepath)
    img = open(savepath, 'rb').read()
    if img is None:
        logger.info("error in loading image:{}".format(image_file))

    # 转为 base64
    data = {'images': [cv2_to_base64(img)]}
    # 发送请求
    url = "http://127.0.0.1:8866/predict/ocr_system"
    headers = {"Content-type": "application/json"}
    r = requests.post(url=url, headers=headers, data=json.dumps(data))

    # 返回结果
    res = r.json()["results"][0]
    logger.info(res)
    return  json.dumps(res)
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

  ####只提取身份证号以及包含带X的####

# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys

__dir__ = os.path.dirname(os.path.abspath(__file__))
sys.path.append(__dir__)
sys.path.append(os.path.abspath(os.path.join(__dir__, '..')))

from ppocr.utils.logging import get_logger

logger = get_logger()

import cv2
import numpy as np
import time
from PIL import Image
from ppocr.utils.utility import get_image_file_list
from tools.infer.utility import draw_ocr, draw_boxes

import requests
import json
import base64

from flask import Flask, request
from flask_cors import CORS
import re

import requests

app = Flask(__name__)
CORS(app)  # 解决跨域问题
sys.setrecursionlimit(10000)  # 解决循环调用限制


def cv2_to_base64(image):
    return base64.b64encode(image).decode('utf8')


def draw_server_result(image_file, res):
    img = cv2.imread(image_file)
    image = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    if len(res) == 0:
        return np.array(image)
    keys = res[0].keys()
    if 'text_region' not in keys:  # for ocr_rec, draw function is invalid
        logger.info("draw function is invalid for ocr_rec!")
        return None
    elif 'text' not in keys:  # for ocr_det
        logger.info("draw text boxes only!")
        boxes = []
        for dno in range(len(res)):
            boxes.append(res[dno]['text_region'])
        boxes = np.array(boxes)
        draw_img = draw_boxes(image, boxes)
        return draw_img
    else:  # for ocr_system
        logger.info("draw boxes and texts!")
        boxes = []
        texts = []
        scores = []
        for dno in range(len(res)):
            boxes.append(res[dno]['text_region'])
            texts.append(res[dno]['text'])
            scores.append(res[dno]['confidence'])
        boxes = np.array(boxes)
        scores = np.array(scores)
        draw_img = draw_ocr(
            image, boxes, texts, scores, draw_txt=True, drop_score=0.5)
        return draw_img


@app.route("/ocr", methods=['POST'])
def ocr_test():
    file = request.files['file']
    image_path = file
    url = "http://127.0.0.1:8866/predict/ocr_system"
    image_file_list = get_image_file_list(image_path)
    is_visualize = False
    headers = {"Content-type": "application/json"}
    cnt = 0
    total_time = 0
    for image_file in image_file_list:
        img = open(image_file, 'rb').read()
        if img is None:
            logger.info("error in loading image:{}".format(image_file))
            continue

        # 发送HTTP请求
        starttime = time.time()
        data = {'images': [cv2_to_base64(img)]}
        r = requests.post(url=url, headers=headers, data=json.dumps(data))
        elapse = time.time() - starttime
        total_time += elapse
        logger.info("Predict time of %s: %.3fs" % (image_file, elapse))
        res = r.json()["results"][0]
        logger.info(res)

        if is_visualize:
            draw_img = draw_server_result(image_file, res)
            if draw_img is not None:
                draw_img_save = "./server_results/"
                if not os.path.exists(draw_img_save):
                    os.makedirs(draw_img_save)
                cv2.imwrite(
                    os.path.join(draw_img_save, os.path.basename(image_file)),
                    draw_img[:, :, ::-1])
                logger.info("The visualized image saved in {}".format(
                    os.path.join(draw_img_save, os.path.basename(image_file))))
        cnt += 1
        if cnt % 100 == 0:
            logger.info("{} processed".format(cnt))
    logger.info("avg time cost: {}".format(float(total_time) / cnt))


@app.route("/test")
def test():
    return 'Hello World!'


@app.route("/recImg", methods=["POST"])
def recImg():
    # 输入参数
    image_file = request.files['file']
    basepath = os.path.dirname(__file__)

    logger.info("{} basepath".format(basepath))

    savepath = os.path.join(basepath, image_file.filename)
    image_file.save(savepath)
    img = open(savepath, 'rb').read()
    if img is None:
        logger.info("error in loading image:{}".format(image_file))

    # 转为 base64
    data = {'images': [cv2_to_base64(img)]}
    # 发送请求
    url = "http://127.0.0.1:8866/predict/ocr_system"
    headers = {"Content-type": "application/json"}
    r = requests.post(url=url, headers=headers, data=json.dumps(data))

    # 返回结果
    res = r.json()["results"][0]
    logger.info(res)
    # 删除保存的img
    os.remove(savepath)
    # 提取身份证号码
    idCardJson = json.dumps(res, ensure_ascii=False)
    return idCardJson


@app.route("/", methods=["POST"])
def myocr():
    # 输入参数
    image_file = request.files['file']
    basepath = os.path.dirname(__file__)

    logger.info("{} basepath".format(basepath))

    savepath = os.path.join(basepath, image_file.filename)
    image_file.save(savepath)
    img = open(savepath, 'rb').read()
    if img is None:
        logger.info("error in loading image:{}".format(image_file))

    # 转为 base64
    data = {'images': [cv2_to_base64(img)]}
    # 发送请求
    url = "http://127.0.0.1:8866/predict/ocr_system"
    headers = {"Content-type": "application/json"}
    r = requests.post(url=url, headers=headers, data=json.dumps(data))

    # 返回结果
    res = r.json()["results"][0]
    logger.info(res)

    # 删除保存的img
    os.remove(savepath)
    # 提取身份证号码
    idCardJson = getIDCard(json.dumps(res, ensure_ascii=False))
    return idCardJson


def getIDCard(text):
    #    logger.info("getIDCard接受的结果 is %s" % (text))
    #    IDs = re.findall(r"d{18}|d{17}[X|x|×]", text)
    #    logger.info("IDs is %s: %s" % (type(IDs), IDs))
    #    if (len(IDs) != 1):
    #        return "Extract IdCard Error"
    #    idDict = {}
    #    idDict['idCard'] = handleIdCard(IDs[0])
    #    idCardJson = json.dumps(idDict, ensure_ascii=False)
    #    return idCardJson

    # 对带X的用户进行处理
    logger.info("getIDCard接受的结果 is %s" % (text))
    # 国内用户
    chIds = re.findall(r"d{18}|d{17}[X|x|×]", text)
    # 港澳用户
    hkIDs = re.findall(r"[H|M]d{8}", text)
    logger.info("chIds is %s: %s" % (type(chIds), chIds))
    logger.info("hkIDs is %s: %s" % (type(hkIDs), hkIDs))
    # len(chIds) != 1 表示只有一个数组
    idDict = {}
    if len(chIds) == 1:
        if len(chIds[0]) == 18:
            idDict['data'] = handleIdCard(chIds[0])
            idDict['code'] = "200"
            return json.dumps(idDict, ensure_ascii=False)

    if len(hkIDs) == 1:
        if len(hkIDs[0]) == 9 and (hkIDs[0].startswith('H') or hkIDs[0].startswith('M')):
            idDict['data'] = hkIDs[0]
            idDict['code'] = "200"
            return json.dumps(idDict, ensure_ascii=False)

    idDict['code'] = "500"
    idDict['data'] = "Extract IdCard Error"
    return json.dumps(idDict, ensure_ascii=False)


def handleIdCard(text):
    if len(text) == 18:
        logger.info("这是啥====== %s" % (text[len(text) - 1]))

        if is_number(text[len(text) - 1]):
            return text
        else:
            return text[0:-1] + "X"


def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        pass

    try:
        import unicodedata
        unicodedata.numeric(s)
        return True
    except (TypeError, ValueError):
        pass
    return False


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
View Code

5、运行与测试

1、启动ocr_system:hub serving start -m ocr_system &
2、启动web服务: python3 test_myocr.py &
   grep: warning: GREP_OPTIONS is deprecated; please use an alias or script

    * Environment: production
    WARNING: This is a development server. Do not use it in a production deployment.
    Use a production WSGI server instead.
    * Debug mode: off
    * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

3、postman 测试与结果

PaddleOCR 安装与实践(CPU版)

这样一个ocr算法程序就部署好了.............

6、转为uwsgi部署

a) 安装 uwsgi

1、卸载pip uninstall uwsgi

2、安装pip install uwsgi --no-cache-dir

参考博客:https://blog.csdn.net/qq_43590972/article/details/88622750

b) 在tools目录下增加myocr.ini

[uwsgi]
#socket配和nginx使用
#socket = 0.0.0.0:8080
#Http请求
http = 0.0.0.0:8080
#项目地址
chdir = /home/PaddleOCR/tools
#flask 请使用app
callable = app
wsgi-file = yangwj.py
processes = 2
threads = 4
#最大支持5M
buffer-size = 5242880
master = true
#支持post请求
post-buffering = 1  
pidfile = uwsgi.pid
#日志文件
daemonize = ./logs/uwsgi.log

c) 清除uwsgi进程和启动uwsgi进程

pkill -9 uwsgi

uwsgi --ini   xxx/uwsgi.ini  #请尽量使用绝对路径

d) 访问地址 http://localhost:8080

==============机器重启后,进入容器步骤==================

1、开启python3的虚拟环境

export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
source ~/.bashrc

2、workon paddleocr

3、docker restart containerId

4、进入容器

sudo docker container exec -it ppocr /bin/bash