diff --git a/deploy/hubserving/ocr_cls/__init__.py b/deploy/hubserving/ocr_cls/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c747d3e7aeca842933e083dffc01ef1fba3f4e85 100644 --- a/deploy/hubserving/ocr_cls/__init__.py +++ b/deploy/hubserving/ocr_cls/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2022 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. \ No newline at end of file diff --git a/deploy/hubserving/ocr_cls/module.py b/deploy/hubserving/ocr_cls/module.py index e159e0d3f23e9654c2d0342fbe6fa86b257ed24b..8b70f0376e5ebf5a960a73115c65a7a1d3d0011e 100644 --- a/deploy/hubserving/ocr_cls/module.py +++ b/deploy/hubserving/ocr_cls/module.py @@ -1,4 +1,17 @@ -# -*- coding:utf-8 -*- +# Copyright (c) 2022 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. + from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -7,7 +20,7 @@ import os import sys sys.path.insert(0, ".") import copy - +import paddlehub from paddlehub.common.logger import logger from paddlehub.module.module import moduleinfo, runnable, serving import cv2 @@ -22,10 +35,10 @@ from deploy.hubserving.ocr_cls.params import read_params @moduleinfo( name="ocr_cls", version="1.0.0", - summary="ocr recognition service", + summary="ocr angle cls service", author="paddle-dev", author_email="paddle-dev@baidu.com", - type="cv/text_recognition") + type="cv/text_angle_cls") class OCRCls(hub.Module): def _initialize(self, use_gpu=False, enable_mkldnn=False): """ @@ -128,6 +141,7 @@ class OCRCls(hub.Module): if __name__ == '__main__': ocr = OCRCls() + ocr._initialize() image_path = [ './doc/imgs_words/ch/word_1.jpg', './doc/imgs_words/ch/word_2.jpg', diff --git a/deploy/hubserving/ocr_cls/params.py b/deploy/hubserving/ocr_cls/params.py index 982f013647b69cdc47c13e6206177fe74849da41..fe4e84843a434e2ca712cdb68d026520de8bf635 100755 --- a/deploy/hubserving/ocr_cls/params.py +++ b/deploy/hubserving/ocr_cls/params.py @@ -1,4 +1,17 @@ -# -*- coding:utf-8 -*- +# Copyright (c) 2022 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. + from __future__ import absolute_import from __future__ import division from __future__ import print_function diff --git a/deploy/hubserving/ocr_det/__init__.py b/deploy/hubserving/ocr_det/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c747d3e7aeca842933e083dffc01ef1fba3f4e85 100644 --- a/deploy/hubserving/ocr_det/__init__.py +++ b/deploy/hubserving/ocr_det/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2022 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. \ No newline at end of file diff --git a/deploy/hubserving/ocr_det/module.py b/deploy/hubserving/ocr_det/module.py index c7d253f5ec8d626279c9eb493e15d1c4c83cfbfd..8fef3be017eef1c6a52395348624f5bfcb6260e7 100644 --- a/deploy/hubserving/ocr_det/module.py +++ b/deploy/hubserving/ocr_det/module.py @@ -1,4 +1,17 @@ -# -*- coding:utf-8 -*- +# Copyright (c) 2022 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. + from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -8,7 +21,7 @@ import sys sys.path.insert(0, ".") import copy - +import paddlehub from paddlehub.common.logger import logger from paddlehub.module.module import moduleinfo, runnable, serving import cv2 @@ -27,7 +40,7 @@ from deploy.hubserving.ocr_system.params import read_params summary="ocr detection service", author="paddle-dev", author_email="paddle-dev@baidu.com", - type="cv/text_recognition") + type="cv/text_detection") class OCRDet(hub.Module): def _initialize(self, use_gpu=False, enable_mkldnn=False): """ @@ -126,6 +139,7 @@ class OCRDet(hub.Module): if __name__ == '__main__': ocr = OCRDet() + ocr._initialize() image_path = [ './doc/imgs/11.jpg', './doc/imgs/12.jpg', diff --git a/deploy/hubserving/ocr_det/params.py b/deploy/hubserving/ocr_det/params.py index 2587a297662cb34d22dbdfe191439e61066cda78..ba41dd07f135402b5878add415c482edf12e2695 100755 --- a/deploy/hubserving/ocr_det/params.py +++ b/deploy/hubserving/ocr_det/params.py @@ -1,4 +1,17 @@ -# -*- coding:utf-8 -*- +# Copyright (c) 2022 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. + from __future__ import absolute_import from __future__ import division from __future__ import print_function diff --git a/deploy/hubserving/ocr_rec/__init__.py b/deploy/hubserving/ocr_rec/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c747d3e7aeca842933e083dffc01ef1fba3f4e85 100644 --- a/deploy/hubserving/ocr_rec/__init__.py +++ b/deploy/hubserving/ocr_rec/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2022 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. \ No newline at end of file diff --git a/deploy/hubserving/ocr_rec/module.py b/deploy/hubserving/ocr_rec/module.py index 2bec3fcdbe00e3693557815b8ed81dd38f0c3b28..9fae54e2a317a7020543675d49fe0b7e07b4f7cd 100644 --- a/deploy/hubserving/ocr_rec/module.py +++ b/deploy/hubserving/ocr_rec/module.py @@ -1,4 +1,17 @@ -# -*- coding:utf-8 -*- +# Copyright (c) 2022 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. + from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -7,7 +20,7 @@ import os import sys sys.path.insert(0, ".") import copy - +import paddlehub from paddlehub.common.logger import logger from paddlehub.module.module import moduleinfo, runnable, serving import cv2 @@ -128,6 +141,7 @@ class OCRRec(hub.Module): if __name__ == '__main__': ocr = OCRRec() + ocr._initialize() image_path = [ './doc/imgs_words/ch/word_1.jpg', './doc/imgs_words/ch/word_2.jpg', diff --git a/deploy/hubserving/ocr_rec/params.py b/deploy/hubserving/ocr_rec/params.py index 5e11c3cfee0c9387fce7f465f15f9424b7b04e9d..70b50dd4d680f744dca5cf1cbe0ebe8f0984d93a 100644 --- a/deploy/hubserving/ocr_rec/params.py +++ b/deploy/hubserving/ocr_rec/params.py @@ -1,4 +1,17 @@ -# -*- coding:utf-8 -*- +# Copyright (c) 2022 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. + from __future__ import absolute_import from __future__ import division from __future__ import print_function diff --git a/deploy/hubserving/ocr_system/__init__.py b/deploy/hubserving/ocr_system/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c747d3e7aeca842933e083dffc01ef1fba3f4e85 100644 --- a/deploy/hubserving/ocr_system/__init__.py +++ b/deploy/hubserving/ocr_system/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2022 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. \ No newline at end of file diff --git a/deploy/hubserving/ocr_system/module.py b/deploy/hubserving/ocr_system/module.py index cbef8086ecff930e272bee16c16e52e2c934b0ad..71a19c6b7049ec1d779377e7c84cbfe7d2820991 100644 --- a/deploy/hubserving/ocr_system/module.py +++ b/deploy/hubserving/ocr_system/module.py @@ -1,4 +1,17 @@ -# -*- coding:utf-8 -*- +# Copyright (c) 2022 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. + from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -9,7 +22,7 @@ sys.path.insert(0, ".") import copy import time - +import paddlehub from paddlehub.common.logger import logger from paddlehub.module.module import moduleinfo, runnable, serving import cv2 @@ -28,7 +41,7 @@ from deploy.hubserving.ocr_system.params import read_params summary="ocr system service", author="paddle-dev", author_email="paddle-dev@baidu.com", - type="cv/text_recognition") + type="cv/PP-OCR_system") class OCRSystem(hub.Module): def _initialize(self, use_gpu=False, enable_mkldnn=False): """ @@ -134,6 +147,7 @@ class OCRSystem(hub.Module): if __name__ == '__main__': ocr = OCRSystem() + ocr._initialize() image_path = [ './doc/imgs/11.jpg', './doc/imgs/12.jpg', diff --git a/deploy/hubserving/ocr_system/params.py b/deploy/hubserving/ocr_system/params.py index 4698e8ce5d8f8c826fe04a85906189e729104ddb..6d74294438cfbc83a8445f994585e7d82ada5f7f 100755 --- a/deploy/hubserving/ocr_system/params.py +++ b/deploy/hubserving/ocr_system/params.py @@ -1,4 +1,17 @@ -# -*- coding:utf-8 -*- +# Copyright (c) 2022 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. + from __future__ import absolute_import from __future__ import division from __future__ import print_function diff --git a/deploy/hubserving/readme.md b/deploy/hubserving/readme.md index b52e3584c36173e4c607dbbd9679605c98de8a67..22699d7122faaab2cdeacad40dff3bbc9f981b03 100755 --- a/deploy/hubserving/readme.md +++ b/deploy/hubserving/readme.md @@ -1,18 +1,34 @@ [English](readme_en.md) | 简体中文 +- [基于PaddleHub Serving的服务部署](#基于paddlehub-serving的服务部署) + - [1. 近期更新](#1-近期更新) + - [2. 快速启动服务](#2-快速启动服务) + - [2.1 准备环境](#21-准备环境) + - [2.2 下载推理模型](#22-下载推理模型) + - [2.3 安装服务模块](#23-安装服务模块) + - [2.4 启动服务](#24-启动服务) + - [2.4.1. 命令行命令启动(仅支持CPU)](#241-命令行命令启动仅支持cpu) + - [2.4.2 配置文件启动(支持CPU、GPU)](#242-配置文件启动支持cpugpu) + - [3. 发送预测请求](#3-发送预测请求) + - [4. 返回结果格式说明](#4-返回结果格式说明) + - [5. 自定义修改服务模块](#5-自定义修改服务模块) + + PaddleOCR提供2种服务部署方式: - 基于PaddleHub Serving的部署:代码路径为"`./deploy/hubserving`",按照本教程使用; - 基于PaddleServing的部署:代码路径为"`./deploy/pdserving`",使用方法参考[文档](../../deploy/pdserving/README_CN.md)。 # 基于PaddleHub Serving的服务部署 -hubserving服务部署目录下包括检测、识别、2阶段串联三种服务包,请根据需求选择相应的服务包进行安装和启动。目录结构如下: +hubserving服务部署目录下包括文本检测、文本方向分类,文本识别、文本检测+文本方向分类+文本识别3阶段串联,表格识别和PP-Structure六种服务包,请根据需求选择相应的服务包进行安装和启动。目录结构如下: ``` deploy/hubserving/ - └─ ocr_cls 分类模块服务包 - └─ ocr_det 检测模块服务包 - └─ ocr_rec 识别模块服务包 - └─ ocr_system 检测+识别串联服务包 + └─ ocr_cls 文本方向分类模块服务包 + └─ ocr_det 文本检测模块服务包 + └─ ocr_rec 文本识别模块服务包 + └─ ocr_system 文本检测+文本方向分类+文本识别串联服务包 + └─ structure_table 表格识别服务包 + └─ structure_system PP-Structure服务包 ``` 每个服务包下包含3个文件。以2阶段串联服务包为例,目录如下: @@ -23,28 +39,32 @@ deploy/hubserving/ocr_system/ └─ module.py 主模块,必选,包含服务的完整逻辑 └─ params.py 参数文件,必选,包含模型路径、前后处理参数等参数 ``` +## 1. 近期更新 -## 快速启动服务 +* 2022.03.30 新增PP-Structure和表格识别两种服务。 + +## 2. 快速启动服务 以下步骤以检测+识别2阶段串联服务为例,如果只需要检测服务或识别服务,替换相应文件路径即可。 -### 1. 准备环境 +### 2.1 准备环境 ```shell # 安装paddlehub # paddlehub 需要 python>3.6.2 -pip3 install paddlehub==2.1.0 --upgrade -i https://pypi.tuna.tsinghua.edu.cn/simple +pip3 install paddlehub==2.1.0 --upgrade -i https://mirror.baidu.com/pypi/simple ``` -### 2. 下载推理模型 +### 2.2 下载推理模型 安装服务模块前,需要准备推理模型并放到正确路径。默认使用的是PP-OCRv2模型,默认模型路径为: ``` 检测模型:./inference/ch_PP-OCRv2_det_infer/ 识别模型:./inference/ch_PP-OCRv2_rec_infer/ 方向分类器:./inference/ch_ppocr_mobile_v2.0_cls_infer/ +表格结构识别模型:./inference/en_ppocr_mobile_v2.0_table_structure_infer/ ``` -**模型路径可在`params.py`中查看和修改。** 更多模型可以从PaddleOCR提供的[模型库](../../doc/doc_ch/models_list.md)下载,也可以替换成自己训练转换好的模型。 +**模型路径可在`params.py`中查看和修改。** 更多模型可以从PaddleOCR提供的模型库[PP-OCR](../../doc/doc_ch/models_list.md)和[PP-Structure](../../ppstructure/docs/models_list.md)下载,也可以替换成自己训练转换好的模型。 -### 3. 安装服务模块 -PaddleOCR提供3种服务模块,根据需要安装所需模块。 +### 2.3 安装服务模块 +PaddleOCR提供5种服务模块,根据需要安装所需模块。 * 在Linux环境下,安装示例如下: ```shell @@ -59,6 +79,12 @@ hub install deploy/hubserving/ocr_rec/ # 或,安装检测+识别串联服务模块: hub install deploy/hubserving/ocr_system/ + +# 或,安装表格识别服务模块: +hub install deploy/hubserving/structure_table/ + +# 或,安装PP-Structure服务模块: +hub install deploy/hubserving/structure_system/ ``` * 在Windows环境下(文件夹的分隔符为`\`),安装示例如下: @@ -74,10 +100,16 @@ hub install deploy\hubserving\ocr_rec\ # 或,安装检测+识别串联服务模块: hub install deploy\hubserving\ocr_system\ + +# 或,安装表格识别服务模块: +hub install deploy\hubserving\structure_table\ + +# 或,安装PP-Structure服务模块: +hub install deploy\hubserving\structure_system\ ``` -### 4. 启动服务 -#### 方式1. 命令行命令启动(仅支持CPU) +### 2.4 启动服务 +#### 2.4.1. 命令行命令启动(仅支持CPU) **启动命令:** ```shell $ hub serving start --modules [Module1==Version1, Module2==Version2, ...] \ @@ -89,7 +121,7 @@ $ hub serving start --modules [Module1==Version1, Module2==Version2, ...] \ **参数:** |参数|用途| -|-|-| +|---|---| |--modules/-m|PaddleHub Serving预安装模型,以多个Module==Version键值对的形式列出
*`当不指定Version时,默认选择最新版本`*| |--port/-p|服务端口,默认为8866| |--use_multiprocess|是否启用并发方式,默认为单进程方式,推荐多核CPU机器使用此方式
*`Windows操作系统只支持单进程方式`*| @@ -99,7 +131,7 @@ $ hub serving start --modules [Module1==Version1, Module2==Version2, ...] \ 这样就完成了一个服务化API的部署,使用默认端口号8866。 -#### 方式2. 配置文件启动(支持CPU、GPU) +#### 2.4.2 配置文件启动(支持CPU、GPU) **启动命令:** ```hub serving start -c config.json``` @@ -136,7 +168,7 @@ export CUDA_VISIBLE_DEVICES=3 hub serving start -c deploy/hubserving/ocr_system/config.json ``` -## 发送预测请求 +## 3. 发送预测请求 配置好服务端,可使用以下命令发送预测请求,获取预测结果: ```python tools/test_hubserving.py server_url image_path``` @@ -144,38 +176,46 @@ hub serving start -c deploy/hubserving/ocr_system/config.json 需要给脚本传递2个参数: - **server_url**:服务地址,格式为 `http://[ip_address]:[port]/predict/[module_name]` -例如,如果使用配置文件启动分类,检测、识别,检测+分类+识别3阶段服务,那么发送请求的url将分别是: +例如,如果使用配置文件启动分类,检测、识别,检测+分类+识别3阶段,表格识别和PP-Structure服务,那么发送请求的url将分别是: `http://127.0.0.1:8865/predict/ocr_det` `http://127.0.0.1:8866/predict/ocr_cls` `http://127.0.0.1:8867/predict/ocr_rec` `http://127.0.0.1:8868/predict/ocr_system` -- **image_path**:测试图像路径,可以是单张图片路径,也可以是图像集合目录路径 +`http://127.0.0.1:8869/predict/structure_table` +`http://127.0.0.1:8870/predict/structure_system` +- **image_dir**:测试图像路径,可以是单张图片路径,也可以是图像集合目录路径 +- **visualize**:是否可视化结果,默认为False +- **output**:可视化结果保存路径,默认为`./hubserving_result` 访问示例: -```python tools/test_hubserving.py http://127.0.0.1:8868/predict/ocr_system ./doc/imgs/``` +```python tools/test_hubserving.py --server_url=http://127.0.0.1:8868/predict/ocr_system --image_dir./doc/imgs/ --visualize=false``` -## 返回结果格式说明 +## 4. 返回结果格式说明 返回结果为列表(list),列表中的每一项为词典(dict),词典一共可能包含3种字段,信息如下: |字段名称|数据类型|意义| -|----|----|----| +|---|---|---| |angle|str|文本角度| |text|str|文本内容| |confidence|float| 文本识别置信度或文本角度分类置信度| |text_region|list|文本位置坐标| +|html|str|表格的html字符串| +|regions|list|版面分析+表格识别+OCR的结果,每一项为一个list,包含表示区域坐标的`bbox`,区域类型的`type`和区域结果的`res`三个字段| 不同模块返回的字段不同,如,文本识别服务模块返回结果不含`text_region`字段,具体信息如下: -| 字段名/模块名 | ocr_det | ocr_cls | ocr_rec | ocr_system | -| ---- | ---- | ---- | ---- | ---- | -|angle| | ✔ | | ✔ | -|text| | |✔|✔| -|confidence| |✔ |✔|✔| -|text_region| ✔| | |✔ | +| 字段名/模块名 | ocr_det | ocr_cls | ocr_rec | ocr_system | structure_table | structure_system | +| --- | --- | --- | --- | --- | --- |--- | +|angle| | ✔ | | ✔ | || +|text| | |✔|✔| | ✔ | +|confidence| |✔ |✔| | | ✔| +|text_region| ✔| | |✔ | | ✔| +|html| | | | |✔ |✔| +|regions| | | | |✔ |✔ | **说明:** 如果需要增加、删除、修改返回字段,可在相应模块的`module.py`文件中进行修改,完整流程参考下一节自定义修改服务模块。 -## 自定义修改服务模块 +## 5. 自定义修改服务模块 如果需要修改服务逻辑,你一般需要操作以下步骤(以修改`ocr_system`为例): - 1、 停止服务 diff --git a/deploy/hubserving/readme_en.md b/deploy/hubserving/readme_en.md index 3bbcf98cd8b78407613e6bdfb5d5ab8b0a25a084..b32e6aa822c55771bbebdf49bb81b9c9202279f5 100755 --- a/deploy/hubserving/readme_en.md +++ b/deploy/hubserving/readme_en.md @@ -1,18 +1,34 @@ English | [简体中文](readme.md) +- [Service deployment based on PaddleHub Serving](#service-deployment-based-on-paddlehub-serving) + - [1. Update](#1-update) + - [2. Quick start service](#2-quick-start-service) + - [2.1 Prepare the environment](#21-prepare-the-environment) + - [2.2 Download inference model](#22-download-inference-model) + - [2.3 Install Service Module](#23-install-service-module) + - [2.4 Start service](#24-start-service) + - [2.4.1 Start with command line parameters (CPU only)](#241-start-with-command-line-parameters-cpu-only) + - [2.4.2 Start with configuration file(CPU、GPU)](#242-start-with-configuration-filecpugpu) + - [3. Send prediction requests](#3-send-prediction-requests) + - [4. Returned result format](#4-returned-result-format) + - [5. User defined service module modification](#5-user-defined-service-module-modification) + + PaddleOCR provides 2 service deployment methods: - Based on **PaddleHub Serving**: Code path is "`./deploy/hubserving`". Please follow this tutorial. - Based on **PaddleServing**: Code path is "`./deploy/pdserving`". Please refer to the [tutorial](../../deploy/pdserving/README.md) for usage. # Service deployment based on PaddleHub Serving -The hubserving service deployment directory includes three service packages: detection, recognition, and two-stage series connection. Please select the corresponding service package to install and start service according to your needs. The directory is as follows: +The hubserving service deployment directory includes six service packages: text detection, text angle class, text recognition, text detection+text angle class+text recognition three-stage series connection, table recognition and PP-Structure. Please select the corresponding service package to install and start service according to your needs. The directory is as follows: ``` deploy/hubserving/ - └─ ocr_det detection module service package - └─ ocr_cls angle class module service package - └─ ocr_rec recognition module service package - └─ ocr_system two-stage series connection service package + └─ ocr_det text detection module service package + └─ ocr_cls text angle class module service package + └─ ocr_rec text recognition module service package + └─ ocr_system text detection+text angle class+text recognition three-stage series connection service package + └─ structure_table table recognition service package + └─ structure_system PP-Structure service package ``` Each service pack contains 3 files. Take the 2-stage series connection service package as an example, the directory is as follows: @@ -23,43 +39,54 @@ deploy/hubserving/ocr_system/ └─ module.py Main module file, required, contains the complete logic of the service └─ params.py Parameter file, required, including parameters such as model path, pre- and post-processing parameters ``` +## 1. Update + +* 2022.03.30 add PP-Structure and table recognition services。 -## Quick start service + +## 2. Quick start service The following steps take the 2-stage series service as an example. If only the detection service or recognition service is needed, replace the corresponding file path. -### 1. Prepare the environment +### 2.1 Prepare the environment ```shell # Install paddlehub # python>3.6.2 is required bt paddlehub pip3 install paddlehub==2.1.0 --upgrade -i https://pypi.tuna.tsinghua.edu.cn/simple ``` -### 2. Download inference model +### 2.2 Download inference model Before installing the service module, you need to prepare the inference model and put it in the correct path. By default, the PP-OCRv2 models are used, and the default model path is: ``` -detection model: ./inference/ch_PP-OCRv2_det_infer/ -recognition model: ./inference/ch_PP-OCRv2_rec_infer/ -text direction classifier: ./inference/ch_ppocr_mobile_v2.0_cls_infer/ +text detection model: ./inference/ch_PP-OCRv2_det_infer/ +text recognition model: ./inference/ch_PP-OCRv2_rec_infer/ +text angle classifier: ./inference/ch_ppocr_mobile_v2.0_cls_infer/ +tanle recognition: ./inference/en_ppocr_mobile_v2.0_table_structure_infer/ ``` **The model path can be found and modified in `params.py`.** More models provided by PaddleOCR can be obtained from the [model library](../../doc/doc_en/models_list_en.md). You can also use models trained by yourself. -### 3. Install Service Module -PaddleOCR provides 3 kinds of service modules, install the required modules according to your needs. +### 2.3 Install Service Module +PaddleOCR provides 5 kinds of service modules, install the required modules according to your needs. * On Linux platform, the examples are as follows. ```shell -# Install the detection service module: +# Install the text detection service module: hub install deploy/hubserving/ocr_det/ -# Or, install the angle class service module: +# Or, install the text angle class service module: hub install deploy/hubserving/ocr_cls/ -# Or, install the recognition service module: +# Or, install the text recognition service module: hub install deploy/hubserving/ocr_rec/ # Or, install the 2-stage series service module: hub install deploy/hubserving/ocr_system/ + +# Or install table recognition service module +hub install deploy/hubserving/structure_table/ + +# Or install PP-Structure service module +hub install deploy/hubserving/structure_system/ ``` * On Windows platform, the examples are as follows. @@ -75,10 +102,16 @@ hub install deploy\hubserving\ocr_rec\ # Or, install the 2-stage series service module: hub install deploy\hubserving\ocr_system\ + +# Or install table recognition service module +hub install deploy/hubserving/structure_table/ + +# Or install PP-Structure service module +hub install deploy\hubserving\structure_system\ ``` -### 4. Start service -#### Way 1. Start with command line parameters (CPU only) +### 2.4 Start service +#### 2.4.1 Start with command line parameters (CPU only) **start command:** ```shell @@ -90,7 +123,7 @@ $ hub serving start --modules [Module1==Version1, Module2==Version2, ...] \ **parameters:** |parameters|usage| -|-|-| +|---|---| |--modules/-m|PaddleHub Serving pre-installed model, listed in the form of multiple Module==Version key-value pairs
*`When Version is not specified, the latest version is selected by default`*| |--port/-p|Service port, default is 8866| |--use_multiprocess|Enable concurrent mode, the default is single-process mode, this mode is recommended for multi-core CPU machines
*`Windows operating system only supports single-process mode`*| @@ -103,7 +136,7 @@ hub serving start -m ocr_system This completes the deployment of a service API, using the default port number 8866. -#### Way 2. Start with configuration file(CPU、GPU) +#### 2.4.2 Start with configuration file(CPU、GPU) **start command:** ```shell hub serving start --config/-c config.json @@ -140,7 +173,7 @@ export CUDA_VISIBLE_DEVICES=3 hub serving start -c deploy/hubserving/ocr_system/config.json ``` -## Send prediction requests +## 3. Send prediction requests After the service starts, you can use the following command to send a prediction request to obtain the prediction result: ```shell python tools/test_hubserving.py server_url image_path @@ -149,19 +182,24 @@ python tools/test_hubserving.py server_url image_path Two parameters need to be passed to the script: - **server_url**:service address,format of which is `http://[ip_address]:[port]/predict/[module_name]` -For example, if the detection, recognition and 2-stage serial services are started with provided configuration files, the respective `server_url` would be: +For example, if using the configuration file to start the text angle classification, text detection, text recognition, detection+classification+recognition 3 stages, table recognition and PP-Structure service, then the `server_url` to send the request will be: + `http://127.0.0.1:8865/predict/ocr_det` `http://127.0.0.1:8866/predict/ocr_cls` `http://127.0.0.1:8867/predict/ocr_rec` `http://127.0.0.1:8868/predict/ocr_system` -- **image_path**:Test image path, can be a single image path or an image directory path +`http://127.0.0.1:8869/predict/structure_table` +`http://127.0.0.1:8870/predict/structure_system` +- **image_dir**:Test image path, can be a single image path or an image directory path +- **visualize**:Whether to visualize the results, the default value is False +- **output**:The floder to save Visualization result, default value is `./hubserving_result` **Eg.** ```shell -python tools/test_hubserving.py http://127.0.0.1:8868/predict/ocr_system ./doc/imgs/ +python tools/test_hubserving.py --server_url=http://127.0.0.1:8868/predict/ocr_system --image_dir./doc/imgs/ --visualize=false` ``` -## Returned result format +## 4. Returned result format The returned result is a list. Each item in the list is a dict. The dict may contain three fields. The information is as follows: |field name|data type|description| @@ -170,19 +208,23 @@ The returned result is a list. Each item in the list is a dict. The dict may con |text|str|text content| |confidence|float|text recognition confidence| |text_region|list|text location coordinates| +|html|str|table html str| +|regions|list|The result of layout analysis + table recognition + OCR, each item is a list, including `bbox` indicating area coordinates, `type` of area type and `res` of area results| The fields returned by different modules are different. For example, the results returned by the text recognition service module do not contain `text_region`. The details are as follows: -| field name/module name | ocr_det | ocr_cls | ocr_rec | ocr_system | -| ---- | ---- | ---- | ---- | ---- | -|angle| | ✔ | | ✔ | -|text| | |✔|✔| -|confidence| |✔ |✔|✔| -|text_region| ✔| | |✔ | +| field name/module name | ocr_det | ocr_cls | ocr_rec | ocr_system | structure_table | structure_system | +| --- | --- | --- | --- | --- | --- |--- | +|angle| | ✔ | | ✔ | || +|text| | |✔|✔| | ✔ | +|confidence| |✔ |✔| | | ✔| +|text_region| ✔| | |✔ | | ✔| +|html| | | | |✔ |✔| +|regions| | | | |✔ |✔ | **Note:** If you need to add, delete or modify the returned fields, you can modify the file `module.py` of the corresponding module. For the complete process, refer to the user-defined modification service module in the next section. -## User defined service module modification +## 5. User defined service module modification If you need to modify the service logic, the following steps are generally required (take the modification of `ocr_system` for example): - 1. Stop service diff --git a/deploy/hubserving/structure_system/__init__.py b/deploy/hubserving/structure_system/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c747d3e7aeca842933e083dffc01ef1fba3f4e85 --- /dev/null +++ b/deploy/hubserving/structure_system/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2022 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. \ No newline at end of file diff --git a/deploy/hubserving/structure_system/config.json b/deploy/hubserving/structure_system/config.json new file mode 100644 index 0000000000000000000000000000000000000000..642aa94a2a25759469f74280f6aab9a2495f493f --- /dev/null +++ b/deploy/hubserving/structure_system/config.json @@ -0,0 +1,16 @@ +{ + "modules_info": { + "structure_system": { + "init_args": { + "version": "1.0.0", + "use_gpu": true + }, + "predict_args": { + } + } + }, + "port": 8870, + "use_multiprocess": false, + "workers": 2 +} + diff --git a/deploy/hubserving/structure_system/module.py b/deploy/hubserving/structure_system/module.py new file mode 100644 index 0000000000000000000000000000000000000000..92846edc6698d0d75224a2b2a844c572fcb17a56 --- /dev/null +++ b/deploy/hubserving/structure_system/module.py @@ -0,0 +1,149 @@ +# Copyright (c) 2022 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. + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import sys +sys.path.insert(0, ".") +import copy + +import time +import paddlehub +from paddlehub.common.logger import logger +from paddlehub.module.module import moduleinfo, runnable, serving +import cv2 +import numpy as np +import paddlehub as hub + +from tools.infer.utility import base64_to_cv2 +from ppstructure.predict_system import StructureSystem as PPStructureSystem +from ppstructure.predict_system import save_structure_res +from ppstructure.utility import parse_args +from deploy.hubserving.structure_system.params import read_params + + +@moduleinfo( + name="structure_system", + version="1.0.0", + summary="PP-Structure system service", + author="paddle-dev", + author_email="paddle-dev@baidu.com", + type="cv/structure_system") +class StructureSystem(hub.Module): + def _initialize(self, use_gpu=False, enable_mkldnn=False): + """ + initialize with the necessary elements + """ + cfg = self.merge_configs() + + cfg.use_gpu = use_gpu + if use_gpu: + try: + _places = os.environ["CUDA_VISIBLE_DEVICES"] + int(_places[0]) + print("use gpu: ", use_gpu) + print("CUDA_VISIBLE_DEVICES: ", _places) + cfg.gpu_mem = 8000 + except: + raise RuntimeError( + "Environment Variable CUDA_VISIBLE_DEVICES is not set correctly. If you wanna use gpu, please set CUDA_VISIBLE_DEVICES via export CUDA_VISIBLE_DEVICES=cuda_device_id." + ) + cfg.ir_optim = True + cfg.enable_mkldnn = enable_mkldnn + + self.table_sys = PPStructureSystem(cfg) + + def merge_configs(self): + # deafult cfg + backup_argv = copy.deepcopy(sys.argv) + sys.argv = sys.argv[:1] + cfg = parse_args() + + update_cfg_map = vars(read_params()) + + for key in update_cfg_map: + cfg.__setattr__(key, update_cfg_map[key]) + + sys.argv = copy.deepcopy(backup_argv) + return cfg + + def read_images(self, paths=[]): + images = [] + for img_path in paths: + assert os.path.isfile( + img_path), "The {} isn't a valid file.".format(img_path) + img = cv2.imread(img_path) + if img is None: + logger.info("error in loading image:{}".format(img_path)) + continue + images.append(img) + return images + + def predict(self, images=[], paths=[]): + """ + Get the chinese texts in the predicted images. + Args: + images (list(numpy.ndarray)): images data, shape of each is [H, W, C]. If images not paths + paths (list[str]): The paths of images. If paths not images + Returns: + res (list): The result of chinese texts and save path of images. + """ + + if images != [] and isinstance(images, list) and paths == []: + predicted_data = images + elif images == [] and isinstance(paths, list) and paths != []: + predicted_data = self.read_images(paths) + else: + raise TypeError("The input data is inconsistent with expectations.") + + assert predicted_data != [], "There is not any image to be predicted. Please check the input data." + + all_results = [] + for img in predicted_data: + if img is None: + logger.info("error in loading image") + all_results.append([]) + continue + starttime = time.time() + res = self.table_sys(img) + elapse = time.time() - starttime + logger.info("Predict time: {}".format(elapse)) + + # parse result + res_final = [] + for region in res: + region.pop('img') + res_final.append(region) + all_results.append({'regions': res_final}) + return all_results + + @serving + def serving_method(self, images, **kwargs): + """ + Run as a service. + """ + images_decode = [base64_to_cv2(image) for image in images] + results = self.predict(images_decode, **kwargs) + return results + + +if __name__ == '__main__': + structure_system = StructureSystem() + structure_system._initialize() + image_path = ['./doc/table/1.png'] + res = structure_system.predict(paths=image_path) + print(res) diff --git a/deploy/hubserving/structure_system/params.py b/deploy/hubserving/structure_system/params.py new file mode 100755 index 0000000000000000000000000000000000000000..3cc6a2794f80bcd68e254b82e45a05eb17811f65 --- /dev/null +++ b/deploy/hubserving/structure_system/params.py @@ -0,0 +1,31 @@ +# Copyright (c) 2022 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. + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from deploy.hubserving.structure_table.params import read_params as table_read_params + + +def read_params(): + cfg = table_read_params() + + # params for layout parser model + cfg.layout_path_model = 'lp://PubLayNet/ppyolov2_r50vd_dcn_365e_publaynet/config' + cfg.layout_label_map = None + + cfg.mode = 'structure' + cfg.output = './output' + return cfg diff --git a/deploy/hubserving/structure_table/__init__.py b/deploy/hubserving/structure_table/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c747d3e7aeca842933e083dffc01ef1fba3f4e85 --- /dev/null +++ b/deploy/hubserving/structure_table/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2022 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. \ No newline at end of file diff --git a/deploy/hubserving/structure_table/config.json b/deploy/hubserving/structure_table/config.json new file mode 100644 index 0000000000000000000000000000000000000000..d0e3cb1523daaec85cc0dc6099969fcfb380184b --- /dev/null +++ b/deploy/hubserving/structure_table/config.json @@ -0,0 +1,16 @@ +{ + "modules_info": { + "structure_table": { + "init_args": { + "version": "1.0.0", + "use_gpu": true + }, + "predict_args": { + } + } + }, + "port": 8869, + "use_multiprocess": false, + "workers": 2 +} + diff --git a/deploy/hubserving/structure_table/module.py b/deploy/hubserving/structure_table/module.py new file mode 100644 index 0000000000000000000000000000000000000000..00393daa037368191201a5afed4aa29a3920c268 --- /dev/null +++ b/deploy/hubserving/structure_table/module.py @@ -0,0 +1,143 @@ +# Copyright (c) 2022 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. + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import sys +sys.path.insert(0, ".") +import copy + +import time +import paddlehub +from paddlehub.common.logger import logger +from paddlehub.module.module import moduleinfo, runnable, serving +import cv2 +import numpy as np +import paddlehub as hub + +from tools.infer.utility import base64_to_cv2 +from ppstructure.table.predict_table import TableSystem as _TableSystem +from ppstructure.predict_system import save_structure_res +from ppstructure.utility import parse_args +from deploy.hubserving.structure_table.params import read_params + + +@moduleinfo( + name="structure_table", + version="1.0.0", + summary="PP-Structure table service", + author="paddle-dev", + author_email="paddle-dev@baidu.com", + type="cv/structure_table") +class TableSystem(hub.Module): + def _initialize(self, use_gpu=False, enable_mkldnn=False): + """ + initialize with the necessary elements + """ + cfg = self.merge_configs() + cfg.use_gpu = use_gpu + if use_gpu: + try: + _places = os.environ["CUDA_VISIBLE_DEVICES"] + int(_places[0]) + print("use gpu: ", use_gpu) + print("CUDA_VISIBLE_DEVICES: ", _places) + cfg.gpu_mem = 8000 + except: + raise RuntimeError( + "Environment Variable CUDA_VISIBLE_DEVICES is not set correctly. If you wanna use gpu, please set CUDA_VISIBLE_DEVICES via export CUDA_VISIBLE_DEVICES=cuda_device_id." + ) + cfg.ir_optim = True + cfg.enable_mkldnn = enable_mkldnn + + self.table_sys = _TableSystem(cfg) + + def merge_configs(self): + # deafult cfg + backup_argv = copy.deepcopy(sys.argv) + sys.argv = sys.argv[:1] + cfg = parse_args() + + update_cfg_map = vars(read_params()) + + for key in update_cfg_map: + cfg.__setattr__(key, update_cfg_map[key]) + + sys.argv = copy.deepcopy(backup_argv) + return cfg + + def read_images(self, paths=[]): + images = [] + for img_path in paths: + assert os.path.isfile( + img_path), "The {} isn't a valid file.".format(img_path) + img = cv2.imread(img_path) + if img is None: + logger.info("error in loading image:{}".format(img_path)) + continue + images.append(img) + return images + + def predict(self, images=[], paths=[]): + """ + Get the chinese texts in the predicted images. + Args: + images (list(numpy.ndarray)): images data, shape of each is [H, W, C]. If images not paths + paths (list[str]): The paths of images. If paths not images + Returns: + res (list): The result of chinese texts and save path of images. + """ + + if images != [] and isinstance(images, list) and paths == []: + predicted_data = images + elif images == [] and isinstance(paths, list) and paths != []: + predicted_data = self.read_images(paths) + else: + raise TypeError("The input data is inconsistent with expectations.") + + assert predicted_data != [], "There is not any image to be predicted. Please check the input data." + + all_results = [] + for img in predicted_data: + if img is None: + logger.info("error in loading image") + all_results.append([]) + continue + starttime = time.time() + pred_html = self.table_sys(img) + elapse = time.time() - starttime + logger.info("Predict time: {}".format(elapse)) + + all_results.append({'html': pred_html}) + return all_results + + @serving + def serving_method(self, images, **kwargs): + """ + Run as a service. + """ + images_decode = [base64_to_cv2(image) for image in images] + results = self.predict(images_decode, **kwargs) + return results + + +if __name__ == '__main__': + table_system = TableSystem() + table_system._initialize() + image_path = ['./doc/table/table.jpg'] + res = table_system.predict(paths=image_path) + print(res) diff --git a/deploy/hubserving/structure_table/params.py b/deploy/hubserving/structure_table/params.py new file mode 100755 index 0000000000000000000000000000000000000000..cc1a73687b22e73346addb35e702254ef67ee8db --- /dev/null +++ b/deploy/hubserving/structure_table/params.py @@ -0,0 +1,31 @@ +# Copyright (c) 2022 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. + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from deploy.hubserving.ocr_system.params import read_params as pp_ocr_read_params + + +def read_params(): + cfg = pp_ocr_read_params() + + # params for table structure model + cfg.table_max_len = 488 + cfg.table_model_dir = './inference/en_ppocr_mobile_v2.0_table_structure_infer/' + cfg.table_char_type = 'en' + cfg.table_char_dict_path = './ppocr/utils/dict/table_structure_dict.txt' + cfg.show_log = False + return cfg diff --git a/paddleocr.py b/paddleocr.py index dc96a5b6e94bae399daef5ce07655b012ee4c0d4..3a06158b0c92ea70e4320646d38e8c9e9295e9db 100644 --- a/paddleocr.py +++ b/paddleocr.py @@ -39,7 +39,7 @@ from ppocr.utils.utility import check_and_read_gif, get_image_file_list from ppocr.utils.network import maybe_download, download_with_progressbar, is_link, confirm_model_dir_url from tools.infer.utility import draw_ocr, str2bool, check_gpu from ppstructure.utility import init_args, draw_structure_result -from ppstructure.predict_system import OCRSystem, save_structure_res +from ppstructure.predict_system import StructureSystem, save_structure_res __all__ = [ 'PaddleOCR', 'PPStructure', 'draw_ocr', 'draw_structure_result', @@ -398,7 +398,7 @@ class PaddleOCR(predict_system.TextSystem): return rec_res -class PPStructure(OCRSystem): +class PPStructure(StructureSystem): def __init__(self, **kwargs): params = parse_args(mMain=False) params.__dict__.update(**kwargs) diff --git a/ppstructure/predict_system.py b/ppstructure/predict_system.py index 3ae52fdd703670c4250f1b4a440004fa8b9082ad..96227aabbbf38904417f3e3a6fd6c49031c4bc58 100644 --- a/ppstructure/predict_system.py +++ b/ppstructure/predict_system.py @@ -22,6 +22,7 @@ sys.path.append(os.path.abspath(os.path.join(__dir__, '..'))) os.environ["FLAGS_allocator_strategy"] = 'auto_growth' import cv2 +import json import numpy as np import time import logging @@ -35,7 +36,7 @@ from ppstructure.utility import parse_args, draw_structure_result logger = get_logger() -class OCRSystem(object): +class StructureSystem(object): def __init__(self, args): self.mode = args.mode if self.mode == 'structure': @@ -66,8 +67,7 @@ class OCRSystem(object): self.use_angle_cls = args.use_angle_cls self.drop_score = args.drop_score elif self.mode == 'vqa': - from ppstructure.vqa.infer_ser_e2e import SerPredictor, draw_ser_results - self.vqa_engine = SerPredictor(args) + raise NotImplementedError def __call__(self, img): if self.mode == 'structure': @@ -82,24 +82,24 @@ class OCRSystem(object): res = self.table_system(roi_img) else: filter_boxes, filter_rec_res = self.text_system(roi_img) - filter_boxes = [x + [x1, y1] for x in filter_boxes] - filter_boxes = [ - x.reshape(-1).tolist() for x in filter_boxes - ] # remove style char style_token = [ '', '', '', '', '', '', '', '', '', '', '', '', '', '' ] - filter_rec_res_tmp = [] - for rec_res in filter_rec_res: + res = [] + for box, rec_res in zip(filter_boxes, filter_rec_res): rec_str, rec_conf = rec_res for token in style_token: if token in rec_str: rec_str = rec_str.replace(token, '') - filter_rec_res_tmp.append((rec_str, rec_conf)) - res = (filter_boxes, filter_rec_res_tmp) + box += [x1, y1] + res.append({ + 'text': rec_str, + 'confidence': float(rec_conf), + 'text_region': box.tolist() + }) res_list.append({ 'type': region.type, 'bbox': [x1, y1, x2, y2], @@ -107,7 +107,7 @@ class OCRSystem(object): 'res': res }) elif self.mode == 'vqa': - res_list, _ = self.vqa_engine(img) + raise NotImplementedError return res_list @@ -123,15 +123,14 @@ def save_structure_res(res, save_folder, img_name): excel_path = os.path.join(excel_save_folder, '{}.xlsx'.format(region['bbox'])) to_excel(region['res'], excel_path) - if region['type'] == 'Figure': + elif region['type'] == 'Figure': roi_img = region['img'] img_path = os.path.join(excel_save_folder, '{}.jpg'.format(region['bbox'])) cv2.imwrite(img_path, roi_img) else: - for box, rec_res in zip(region['res'][0], region['res'][1]): - f.write('{}\t{}\n'.format( - np.array(box).reshape(-1).tolist(), rec_res)) + for text_result in region['res']: + f.write('{}\n'.format(json.dumps(text_result))) def main(args): @@ -139,7 +138,7 @@ def main(args): image_file_list = image_file_list image_file_list = image_file_list[args.process_id::args.total_process_num] - structure_sys = OCRSystem(args) + structure_sys = StructureSystem(args) img_num = len(image_file_list) save_folder = os.path.join(args.output, structure_sys.mode) os.makedirs(save_folder, exist_ok=True) @@ -162,8 +161,9 @@ def main(args): draw_img = draw_structure_result(img, res, args.vis_font_path) img_save_path = os.path.join(save_folder, img_name, 'show.jpg') elif structure_sys.mode == 'vqa': - draw_img = draw_ser_results(img, res, args.vis_font_path) - img_save_path = os.path.join(save_folder, img_name + '.jpg') + raise NotImplementedError + # draw_img = draw_ser_results(img, res, args.vis_font_path) + # img_save_path = os.path.join(save_folder, img_name + '.jpg') cv2.imwrite(img_save_path, draw_img) logger.info('result save to {}'.format(img_save_path)) elapse = time.time() - starttime diff --git a/ppstructure/utility.py b/ppstructure/utility.py index 43cb0b0873812baf3ce2dc689fb62f1d0ca2c551..10d9f71a7cdfed00b555c46689b2dd3c5aad807c 100644 --- a/ppstructure/utility.py +++ b/ppstructure/utility.py @@ -40,12 +40,6 @@ def init_args(): type=ast.literal_eval, default=None, help='label map according to ppstructure/layout/README_ch.md') - # params for ser - parser.add_argument("--model_name_or_path", type=str) - parser.add_argument("--max_seq_length", type=int, default=512) - parser.add_argument( - "--label_map_path", type=str, default='./vqa/labels/labels_ser.txt') - parser.add_argument( "--mode", type=str, @@ -67,10 +61,10 @@ def draw_structure_result(image, result, font_path): if region['type'] == 'Table': pass else: - for box, rec_res in zip(region['res'][0], region['res'][1]): - boxes.append(np.array(box).reshape(-1, 2)) - txts.append(rec_res[0]) - scores.append(rec_res[1]) + for text_result in region['res']: + boxes.append(np.array(text_result['text_region'])) + txts.append(text_result['text']) + scores.append(text_result['confidence']) im_show = draw_ocr_box_txt( image, boxes, txts, scores, font_path=font_path, drop_score=0) return im_show diff --git a/tools/test_hubserving.py b/tools/test_hubserving.py index 0548726417699855a3905fa1a3fb679d69c85fc8..ec17a9413e15b3ae92843990cfcbb05fc5f991a8 100755 --- a/tools/test_hubserving.py +++ b/tools/test_hubserving.py @@ -25,7 +25,9 @@ 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 +from tools.infer.utility import draw_ocr, draw_boxes, str2bool +from ppstructure.utility import draw_structure_result +from ppstructure.predict_system import to_excel import requests import json @@ -69,8 +71,33 @@ def draw_server_result(image_file, res): return draw_img -def main(url, image_path): - image_file_list = get_image_file_list(image_path) +def save_structure_res(res, save_folder, image_file): + img = cv2.imread(image_file) + excel_save_folder = os.path.join(save_folder, os.path.basename(image_file)) + os.makedirs(excel_save_folder, exist_ok=True) + # save res + with open( + os.path.join(excel_save_folder, 'res.txt'), 'w', + encoding='utf8') as f: + for region in res: + if region['type'] == 'Table': + excel_path = os.path.join(excel_save_folder, + '{}.xlsx'.format(region['bbox'])) + to_excel(region['res'], excel_path) + elif region['type'] == 'Figure': + x1, y1, x2, y2 = region['bbox'] + print(region['bbox']) + roi_img = img[y1:y2, x1:x2, :] + img_path = os.path.join(excel_save_folder, + '{}.jpg'.format(region['bbox'])) + cv2.imwrite(img_path, roi_img) + else: + for text_result in region['res']: + f.write('{}\n'.format(json.dumps(text_result))) + + +def main(args): + image_file_list = get_image_file_list(args.image_dir) is_visualize = False headers = {"Content-type": "application/json"} cnt = 0 @@ -80,38 +107,51 @@ def main(url, image_path): if img is None: logger.info("error in loading image:{}".format(image_file)) continue - - # 发送HTTP请求 + img_name = os.path.basename(image_file) + # seed http request starttime = time.time() data = {'images': [cv2_to_base64(img)]} - r = requests.post(url=url, headers=headers, data=json.dumps(data)) + r = requests.post( + url=args.server_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 args.visualize: + draw_img = None + if 'structure_table' in args.server_url: + to_excel(res['html'], './{}.xlsx'.format(img_name)) + elif 'structure_system' in args.server_url: + save_structure_res(res['regions'], args.output, image_file) + else: + 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) + if not os.path.exists(args.output): + os.makedirs(args.output) cv2.imwrite( - os.path.join(draw_img_save, os.path.basename(image_file)), + os.path.join(args.output, 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)))) + os.path.join(args.output, 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)) +def parse_args(): + import argparse + parser = argparse.ArgumentParser(description="args for hub serving") + parser.add_argument("--server_url", type=str, required=True) + parser.add_argument("--image_dir", type=str, required=True) + parser.add_argument("--visualize", type=str2bool, default=False) + parser.add_argument("--output", type=str, default='./hubserving_result') + args = parser.parse_args() + return args + + if __name__ == '__main__': - if len(sys.argv) != 3: - logger.info("Usage: %s server_url image_path" % sys.argv[0]) - else: - server_url = sys.argv[1] - image_path = sys.argv[2] - main(server_url, image_path) + args = parse_args() + main(args)