使用Flask部署ppocr模型_3

PaddleOCR环境搭建、模型训练、推理、部署全流程(Ubuntu系统)_1_paddle 多进程推理-CSDN博客

PP-Structure 文档分析-CSDN博客

Pycharm的Terminal进入创建好的虚拟环境

有时候Pycharm的terminal中显示的是硬盘中的项目路径,但没有进入创建好的虚拟环境

这时候,在Pycharm>File>Tools>Terminal中切换powershell.exe为cmd.exe

接前两篇继续完成Flask部署

一、使用Flask部署ppocr模型

 GET方法用于从服务器获取资源,即客户端向服务器请求数据。POST方法用于向服务器提交数据,即客户端向服务器发送数据。

  1.  服务器:一般是指    http://127.0.0.1:5000
  2. 客户端:一般是指网页

点击提交按钮,会触发flask的post请求

目录结构

'static/images' 文件夹用来存放上传过来的图片

‘templates’文件夹下的两个html文件定义显示页面

templates这个文件在里面的作用:

在Flask框架中,templates文件夹是一个特定的目录,用于存放Web应用的HTML模板文件。这些模板文件使用Jinja2模板语言编写,允许开发者将动态内容(如从数据库获取的数据、用户输入、计算结果等)与静态HTML结构相结合,生成最终发送给客户端的HTML响应。

作用与特性

  1. 分离视图与逻辑

    • templates文件夹中的模板文件专注于呈现用户界面(UI),即HTML结构和样式。这使得视图层(UI设计)与业务逻辑(Python代码)得以分离,提高了代码的可维护性和复用性。
  2. 动态内容填充

    • 在模板文件中,可以使用Jinja2语法插入变量、控制结构(如条件语句、循环)、过滤器(对数据进行格式化)等。当Flask收到请求并渲染模板时,会将Python代码中传递的上下文数据(字典对象)与模板中的占位符匹配,动态生成包含具体数据的HTML页面。
  3. 继承与宏

    • templates文件夹中的模板可以互相继承,实现布局的复用。一个基础模板(如base.html)可以定义网站的通用结构(如头部、导航栏、页脚等),其他具体的页面模板(如index.htmlprofile.html等)则继承基础模板,并在其内部填充特定的内容区域。此外,Jinja2还支持定义和使用宏(类似于函数),封装重复使用的HTML片段。
  4. 组织结构

    • templates文件夹通常按照应用的结构进行组织,例如创建子目录来存放不同模块或蓝本(Blueprint)对应的模板。这种结构化方式有助于保持项目整洁,便于查找和管理相关模板。

工作流程

  1. 路由定义

    • 在Flask应用中,通过@app.route装饰器定义路由,如@app.route('/')表示处理根URL(http://example.com/)的请求。
  2. 视图函数

    • 对应路由的视图函数(如def index():)负责处理HTTP请求,执行必要的业务逻辑,并准备要传递给模板的数据(通常以字典形式)。
  3. 渲染模板

    • 视图函数调用render_template()函数,传入模板文件名(如'index.html')和上下文数据。Flask自动在templates文件夹中查找指定的模板,并使用Jinja2引擎渲染模板,将动态数据填充到相应的位置。
  4. 响应生成

    • 渲染后的HTML字符串作为HTTP响应的主体,发送回客户端(如浏览器),用户最终看到的就是根据模板动态生成的网页。

总之,templates文件夹在Flask应用中起着至关重要的作用,它承载了Web应用的用户界面设计,并通过Jinja2模板语言与应用的业务逻辑紧密协作,共同构建出丰富的动态Web页面

服务器程序——载入模型,命名app.py 

import numpy as np
from flask import Flask, request, jsonify, render_template
import pickle
 
app = Flask(__name__)
model = pickle.load(open('model.pkl','rb'))
 
@app.route('/')
def home():
    return render_template('page.html')
 
@app.route('/predict', methods=['POST'])
def predict():
    features_list = [float(x) for x in request.form.values()]
    features = np.array(features_list).reshape(1,-1)
    predict_outcome_list = model.predict(features)
    predict_outcome = round(predict_outcome_list[0],2)
 
    return render_template('page.html',prediction_display_area='预测价格为:{}'.format(predict_outcome))
 
if __name__ == "__main__":
    app.run(port=80,debug = True)

部署PaddleOCR(PP-OCR)模型到Flask应用中,通常包括以下几个步骤:

1、环境准备与模型获取

安装依赖:确保已经安装了Flask,以及PaddlePaddle(PaddleOCR的依赖库)

下载模型

(继续前两篇所以模型和环境不在重复)

2、创建Flask应用

        初始化Flask app:编写Python脚本,创建一个新的Flask应用实例。

from flask import Flask, request, jsonify

app = Flask(__name__)

        定义路由与处理函数:创建一个路由(如/predict),并编写对应的处理函数,该函数接收HTTP请求中的图像数据,调用PaddleOCR进行识别,并返回识别结果。

@app.route('/predict', methods=['POST'])
def ocr_predict():
    # 获取请求中的图像数据
    image_data = request.files.get('image')
    # 使用PaddleOCR进行识别
    result = ocr_api(image_data)
    # 返回JSON格式的结果
    return jsonify(result)

3、加载与封装PaddleOCR

        加载模型:在Flask应用中,使用PaddleOCR提供的API加载模型。指定模型路径和所需配置

from paddleocr import PaddleOCR

ocr = PaddleOCR(model_path='path/to/model', config_path='path/to/config.json')

        封装识别接口:创建一个名为ocr_api的函数,接受图像数据作为输入,使用加载的OCR对象进行识别,并处理返回结果。可能需要对图像数据进行预处理(如解码、缩放),然后调用OCR的ocr方法。

def ocr_api(image_data):
    img_bytes = image_data.read()
    img = cv2.imdecode(np.frombuffer(img_bytes, np.uint8), cv2.IMREAD_COLOR)
    results = ocr.ocr(img)
    # 对结果进行整理,例如提取文字和其坐标
    formatted_results = []
    for res in results:
        text, box, _ = res
        formatted_results.append({
            'text': text,
            'bbox': box.tolist()
        })
    return formatted_results

4、处理图像

        根据Flask接收到的HTTP请求类型(如multipart/form-data),解析上传的图像数据。上述示例中,假设图像通过名为image的字段以文件形式上传

5、配置运行参数:

        设置Flask应用的运行参数,如主机地址、端口、调试模式等。例如:

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5001, debug=True)

6、部署与测试
  • 启动Flask应用。在命令行中运行包含以上代码的Python脚本。
  • 使用HTTP客户端(如Postman)或编写简单的HTML表单,向http://localhost:5001/predict发送POST请求,附带上要识别的图像文件。检查响应是否包含预期的OCR识别结果

代码:

# 环境ppocr/001

import os
import subprocess
import shutil
from flask import Flask, render_template, request, jsonify

app = Flask(__name__)


file = 'D:/GPT_1/ppocr_1/ppstructure/table/predict_table.py'
det_model = 'D:/GPT_1/ppocr_1/ppstructure/inference/ch_PP-OCRv3_det_infer'
rec_model = 'D:/GPT_1/ppocr_1/ppstructure/inference/ch_PP-OCRv3_rec_infer'
table_model = 'D:/GPT_1/ppocr_1/ppstructure/inference/ch_ppstructure_mobile_v2.0_SLANet_infer'
rec_dict = 'D:/GPT_1/ppocr_1/ppocr/utils/ppocr_keys_v1.txt'
table_dict = 'D:/GPT_1/ppocr_1/ppocr/utils/dict/table_structure_dict_ch.txt'
output = 'D:/GPT_1/ppocr_1/ppocrtable_Flask/static/output/table'


def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1] in set(['bmp', 'jpg', 'JPG', 'png', 'PNG'])


@app.route('/', methods=['GET'])
def index():
    return render_template('index.html')


@app.route('/Upload', methods=['POST', 'GET'])  # 添加路由
def classification():
    if request.method == 'POST':
        f = request.files['images']
        if not (f and allowed_file(f.filename)):
            return jsonify({"error": 1001, "msg": "only support image formats: .bmp .png .PNG .jpg .JPG"})

        basepath = os.path.dirname(__file__)  # 当前文件所在路径

        if os.path.exists('static/images/test.jpg'):
            os.remove('static/images/test.jpg')
            pass
        else:
            pass

        if os.path.exists('static/output/table'):
            shutil.rmtree('static/output/table')
            pass
        else:
            pass

        upload_path = os.path.join(basepath, 'static/images/test.jpg')  # 注意:没有的文件夹一定要先创建,不然会提示没有该路径
        f.save(upload_path)
        f_name = f.filename

        # image = cv2.imread(upload_path)
        # image = image.astype(np.float32)
        # image_array = np.array(image)
        # input_data = np.expand_dims(image_array, axis=-0)

        cmd = ['python',
               '{}'.format(file),
               '--det_model_dir={}'.format(det_model),
               '--rec_model_dir={}'.format(rec_model),
               '--table_model_dir={}'.format(table_model),
               '--rec_char_dict_path={}'.format(rec_dict),
               '--table_char_dict_path={}'.format(table_dict),
               '--image_dir={}'.format(upload_path),
               '--output={}'.format(output)]

        # 使用Popen创建进程,并与进程进行复杂的交互
        proc = subprocess.Popen(
            cmd,  # cmd特定的查询空间的命令
            stdin=None,  # 标准输入 键盘
            stdout=subprocess.PIPE,  # -1 标准输出(演示器、终端) 保存到管道中以便进行操作
            stderr=subprocess.PIPE,  # 标准错误,保存到管道# #
        )
        outinfo, errinfo = proc.communicate()  # 获取输出和错误信息
        print('----------')
        print(outinfo)
        print(errinfo)
        print('-------')

        return render_template('return.html', info=outinfo.decode('utf-8'), img_name=f_name,
                               file_loc=os.getcwd() + '\static\output\\table\show.html')

    return render_template('index.html')


if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000, debug=True)

代码详解:

# 环境ppocr/001

import os
import subprocess
import shutil
from flask import Flask, render_template, request, jsonify

app = Flask(__name__)

# 除了output外其它写成绝对路径
# inference里的是自己训练好或官方的推理模型
file = '/home/sxj/GPT_1/ppocr_1/ppstructure/table/predict_table.py'
det_model = '/home/sxj/GPT_1/ppocr_1/ppstructure/inference/ch_PP-OCRv3_det_infer'
rec_model = '/home/sxj/GPT_1/ppocr_1/ppstructure/inference/ch_PP-OCRv3_rec_infer'
table_model = '/home/sxj/GPT_1/ppocr_1/ppstructure/inference/ch_ppstructure_mobile_v2.0_SLANet_infer'
rec_dict = '/home/sxj/GPT_1/ppocr_1/ppocr/utils/ppocr_keys_v1.txt'
table_dict = '/home/sxj/GPT_1/ppocr_1/ppocr/utils/dict/table_structure_dict_ch.txt'
output = '/home/sxj/GPT_1/ppocr_1/ppocrtable_Flask/static/output/table'

# file: PaddleOCR表格预测脚本的路径。
# det_model, rec_model, table_model: 用于文本检测、文本识别和表格结构识别的模型文件路径。
# rec_dict, table_dict: 文本识别和表格结构识别所需的字符字典文件路径。
# output: 应用运行时生成的输出文件(如表格识别结果)的保存目录

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1] in set(['bmp', 'jpg', 'JPG', 'png', 'PNG'])


@app.route('/', methods=['GET'])
def index():
    return render_template('index.html')

# 定义Flask路由,当访问应用根URL(http://localhost:5000/)时,调用index函数。该函数返回渲染后的index.html模板作为HTTP响应

@app.route('/Upload', methods=['POST', 'GET'])  # 添加路由
def classification():
    if request.method == 'POST':
        # 定义另一个Flask路由,当访问 / Upload
        # URL且请求方法为POST或GET时,调用classification函数。函数内部首先判断请求方法是否为POST,如果是,则执行上传图片和表格识别的逻辑;
        # 否则(即请求方法为GET时),返回渲染后的index.html模板。
        # 接下来是classification函数内部的POST请求处理逻辑:
        f = request.files['images']
        if not (f and allowed_file(f.filename)):
            return jsonify({"error": 1001, "msg": "only support image formats: .bmp .png .PNG .jpg .JPG"})

        # 从请求对象中获取上传的文件(假设表单字段名为images),并使用allowed_file函数检查文件格式。如果不满足条件,返回包含错误码和消息的JSON响应


        basepath = os.path.dirname(__file__)  # 当前文件所在路径

        if os.path.exists('static/images/test.jpg'):
            os.remove('static/images/test.jpg')
            pass
        else:
            pass

        if os.path.exists('static/output/table'):
            shutil.rmtree('static/output/table')
            pass
        else:
            pass
        # 获取当前文件(app.py)所在的路径,并在此基础上删除旧的测试图片和清理输出目录(如果存在)

        upload_path = os.path.join(basepath, 'static/images/test.jpg')  # 注意:没有的文件夹一定要先创建,不然会提示没有该路径
        f.save(upload_path)
        f_name = f.filename
        # 将上传的图片保存到指定路径,并记录文件名

        # image = cv2.imread(upload_path)
        # image = image.astype(np.float32)
        # image_array = np.array(image)
        # input_data = np.expand_dims(image_array, axis=-0)

        cmd = ['python',
               '{}'.format(file),
               '--det_model_dir={}'.format(det_model),
               '--rec_model_dir={}'.format(rec_model),
               '--table_model_dir={}'.format(table_model),
               '--rec_char_dict_path={}'.format(rec_dict),
               '--table_char_dict_path={}'.format(table_dict),
               '--image_dir={}'.format(upload_path),
               '--output={}'.format(output)]
        # --det_model_dir = {}: 同样使用format()方法插入变量值。这里插入的是det_model变量
        # 这是一个命令行选项,告诉表格预测脚本使用指定的检测模型。
        # 格式化后为 - -output = / home / sxj / GPT_1 / ppocr_1 / ppocrtable_Flask / static / output / table,告诉脚本将识别结果保存到此目录。
        # 构造用于执行表格预测脚本的命令行参数列表

        # 使用Popen创建进程,并与进程进行复杂的交互
        proc = subprocess.Popen(
            cmd,  # cmd特定的查询空间的命令
            stdin=None,  # 标准输入 键盘
            stdout=subprocess.PIPE,  # -1 标准输出(演示器、终端) 保存到管道中以便进行操作
            stderr=subprocess.PIPE,  # 标准错误,保存到管道# #
        )
        outinfo, errinfo = proc.communicate()  # 获取输出和错误信息
        print('----------')
        print(outinfo)
        print(errinfo)
        print('-------')
        # 使用subprocess.Popen创建子进程,执行表格预测脚本,并通过管道获取子进程的输出和错误信息。打印这些信息以辅助调试

        return render_template('return.html', info=outinfo.decode('utf-8'), img_name=f_name,
                               file_loc=os.getcwd() + '\static\output\\table\show.html')
    # 在子进程执行成功后,返回渲染后的return.html模板作为HTTP响应,其中包含表格识别结果(info)、上传图片的文件名(img_name)以及输出文件(show.html)的相对路径

    return render_template('index.html')


if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000, debug=True)
# 如果当前脚本作为主程序运行(而不是作为模块导入),则启动Flask应用。设置监听所有网络接口(host="0.0.0.0")、监听端口为5000(port=5000),并开启调试模式(debug=True)

接下来做内网穿透部署

内网穿透部署的主要作用是使得内网中的服务能够被外部用户访问,从而扩大了服务的覆盖范围。具体来说,它有以下几方面的应用:

  1. 远程办公与灵活性提升:通过内网穿透,员工可以在任何地方安全地访问公司的内部资源,如文件共享、内部网站、数据库等,从而提高了工作的灵活性和效率。
  2. 远程开发与调试:对于开发人员而言,内网穿透可以使其将本地开发环境暴露给外部网络,方便团队成员或客户远程访问和测试应用程序,从而加快开发周期和提高协作效率。
  3. 设备远程管理与控制:通过内网穿透,用户可以远程访问和管理路由器、摄像头、网络存储等设备,实现远程管理和控制。
  4. 数据远程同步与安全性保障:一些企业由于安全考虑,不愿将数据库放到云服务器上。内网穿透可以将数据库放在办公室本地,然后通过特定的传输通道实现数据的远程同步和访问,既保证了安全又保证了公网的正常访问。
  5. 搭建局域网服务器服务:内网穿透使得用户可以搭建FTP服务器、Web服务器等,并提供外网访问功能。
  6. 其他应用:内网穿透还可以用于远程监控设备的运行状况、实现远程联机游戏、文件远程共享等。

总的来说,内网穿透部署通过技术手段将内网中的服务暴露给外部网络,不仅扩大了服务的覆盖范围,还提高了工作效率和便利性,为远程办公、家庭安防、开发测试等提供了方便的解决方案

参考:内网穿透(详细且免费)部署(现已推出新的源码 搭建网站和云盘)_内网穿透服务器搭建-CSDN博客

参考:flask部署深度学习pytorch模型_flsak部署pytorch深度学习模型-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值