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方法用于向服务器提交数据,即客户端向服务器发送数据。
-
服务器:一般是指 http://127.0.0.1:5000
-
客户端:一般是指网页
点击提交按钮,会触发flask的post请求
目录结构
'static/images' 文件夹用来存放上传过来的图片
‘templates’文件夹下的两个html文件定义显示页面
templates这个文件在里面的作用:
在Flask框架中,templates
文件夹是一个特定的目录,用于存放Web应用的HTML模板文件。这些模板文件使用Jinja2模板语言编写,允许开发者将动态内容(如从数据库获取的数据、用户输入、计算结果等)与静态HTML结构相结合,生成最终发送给客户端的HTML响应。
作用与特性:
-
分离视图与逻辑:
templates
文件夹中的模板文件专注于呈现用户界面(UI),即HTML结构和样式。这使得视图层(UI设计)与业务逻辑(Python代码)得以分离,提高了代码的可维护性和复用性。
-
动态内容填充:
- 在模板文件中,可以使用Jinja2语法插入变量、控制结构(如条件语句、循环)、过滤器(对数据进行格式化)等。当Flask收到请求并渲染模板时,会将Python代码中传递的上下文数据(字典对象)与模板中的占位符匹配,动态生成包含具体数据的HTML页面。
-
继承与宏:
templates
文件夹中的模板可以互相继承,实现布局的复用。一个基础模板(如base.html
)可以定义网站的通用结构(如头部、导航栏、页脚等),其他具体的页面模板(如index.html
、profile.html
等)则继承基础模板,并在其内部填充特定的内容区域。此外,Jinja2还支持定义和使用宏(类似于函数),封装重复使用的HTML片段。
-
组织结构:
templates
文件夹通常按照应用的结构进行组织,例如创建子目录来存放不同模块或蓝本(Blueprint)对应的模板。这种结构化方式有助于保持项目整洁,便于查找和管理相关模板。
工作流程:
-
路由定义:
- 在Flask应用中,通过
@app.route
装饰器定义路由,如@app.route('/')
表示处理根URL(http://example.com/
)的请求。
- 在Flask应用中,通过
-
视图函数:
- 对应路由的视图函数(如
def index():
)负责处理HTTP请求,执行必要的业务逻辑,并准备要传递给模板的数据(通常以字典形式)。
- 对应路由的视图函数(如
-
渲染模板:
- 视图函数调用
render_template()
函数,传入模板文件名(如'index.html'
)和上下文数据。Flask自动在templates
文件夹中查找指定的模板,并使用Jinja2引擎渲染模板,将动态数据填充到相应的位置。
- 视图函数调用
-
响应生成:
- 渲染后的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)
接下来做内网穿透部署
内网穿透部署的主要作用是使得内网中的服务能够被外部用户访问,从而扩大了服务的覆盖范围。具体来说,它有以下几方面的应用:
- 远程办公与灵活性提升:通过内网穿透,员工可以在任何地方安全地访问公司的内部资源,如文件共享、内部网站、数据库等,从而提高了工作的灵活性和效率。
- 远程开发与调试:对于开发人员而言,内网穿透可以使其将本地开发环境暴露给外部网络,方便团队成员或客户远程访问和测试应用程序,从而加快开发周期和提高协作效率。
- 设备远程管理与控制:通过内网穿透,用户可以远程访问和管理路由器、摄像头、网络存储等设备,实现远程管理和控制。
- 数据远程同步与安全性保障:一些企业由于安全考虑,不愿将数据库放到云服务器上。内网穿透可以将数据库放在办公室本地,然后通过特定的传输通道实现数据的远程同步和访问,既保证了安全又保证了公网的正常访问。
- 搭建局域网服务器服务:内网穿透使得用户可以搭建FTP服务器、Web服务器等,并提供外网访问功能。
- 其他应用:内网穿透还可以用于远程监控设备的运行状况、实现远程联机游戏、文件远程共享等。
总的来说,内网穿透部署通过技术手段将内网中的服务暴露给外部网络,不仅扩大了服务的覆盖范围,还提高了工作效率和便利性,为远程办公、家庭安防、开发测试等提供了方便的解决方案
参考:内网穿透(详细且免费)部署(现已推出新的源码 搭建网站和云盘)_内网穿透服务器搭建-CSDN博客
参考:flask部署深度学习pytorch模型_flsak部署pytorch深度学习模型-CSDN博客