未验证 提交 69269c16 编写于 作者: Z zhoujun 提交者: GitHub

Merge pull request #5840 from WenmuZhou/cpp_infer

add PP-Structure to hubserving
# 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
# -*- 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 absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
...@@ -7,7 +20,7 @@ import os ...@@ -7,7 +20,7 @@ import os
import sys import sys
sys.path.insert(0, ".") sys.path.insert(0, ".")
import copy import copy
import paddlehub
from paddlehub.common.logger import logger from paddlehub.common.logger import logger
from paddlehub.module.module import moduleinfo, runnable, serving from paddlehub.module.module import moduleinfo, runnable, serving
import cv2 import cv2
...@@ -22,10 +35,10 @@ from deploy.hubserving.ocr_cls.params import read_params ...@@ -22,10 +35,10 @@ from deploy.hubserving.ocr_cls.params import read_params
@moduleinfo( @moduleinfo(
name="ocr_cls", name="ocr_cls",
version="1.0.0", version="1.0.0",
summary="ocr recognition service", summary="ocr angle cls service",
author="paddle-dev", author="paddle-dev",
author_email="paddle-dev@baidu.com", author_email="paddle-dev@baidu.com",
type="cv/text_recognition") type="cv/text_angle_cls")
class OCRCls(hub.Module): class OCRCls(hub.Module):
def _initialize(self, use_gpu=False, enable_mkldnn=False): def _initialize(self, use_gpu=False, enable_mkldnn=False):
""" """
...@@ -128,6 +141,7 @@ class OCRCls(hub.Module): ...@@ -128,6 +141,7 @@ class OCRCls(hub.Module):
if __name__ == '__main__': if __name__ == '__main__':
ocr = OCRCls() ocr = OCRCls()
ocr._initialize()
image_path = [ image_path = [
'./doc/imgs_words/ch/word_1.jpg', './doc/imgs_words/ch/word_1.jpg',
'./doc/imgs_words/ch/word_2.jpg', './doc/imgs_words/ch/word_2.jpg',
......
# -*- 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 absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
......
# 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
# -*- 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 absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
...@@ -8,7 +21,7 @@ import sys ...@@ -8,7 +21,7 @@ import sys
sys.path.insert(0, ".") sys.path.insert(0, ".")
import copy import copy
import paddlehub
from paddlehub.common.logger import logger from paddlehub.common.logger import logger
from paddlehub.module.module import moduleinfo, runnable, serving from paddlehub.module.module import moduleinfo, runnable, serving
import cv2 import cv2
...@@ -27,7 +40,7 @@ from deploy.hubserving.ocr_system.params import read_params ...@@ -27,7 +40,7 @@ from deploy.hubserving.ocr_system.params import read_params
summary="ocr detection service", summary="ocr detection service",
author="paddle-dev", author="paddle-dev",
author_email="paddle-dev@baidu.com", author_email="paddle-dev@baidu.com",
type="cv/text_recognition") type="cv/text_detection")
class OCRDet(hub.Module): class OCRDet(hub.Module):
def _initialize(self, use_gpu=False, enable_mkldnn=False): def _initialize(self, use_gpu=False, enable_mkldnn=False):
""" """
...@@ -126,6 +139,7 @@ class OCRDet(hub.Module): ...@@ -126,6 +139,7 @@ class OCRDet(hub.Module):
if __name__ == '__main__': if __name__ == '__main__':
ocr = OCRDet() ocr = OCRDet()
ocr._initialize()
image_path = [ image_path = [
'./doc/imgs/11.jpg', './doc/imgs/11.jpg',
'./doc/imgs/12.jpg', './doc/imgs/12.jpg',
......
# -*- 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 absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
......
# 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
# -*- 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 absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
...@@ -7,7 +20,7 @@ import os ...@@ -7,7 +20,7 @@ import os
import sys import sys
sys.path.insert(0, ".") sys.path.insert(0, ".")
import copy import copy
import paddlehub
from paddlehub.common.logger import logger from paddlehub.common.logger import logger
from paddlehub.module.module import moduleinfo, runnable, serving from paddlehub.module.module import moduleinfo, runnable, serving
import cv2 import cv2
...@@ -128,6 +141,7 @@ class OCRRec(hub.Module): ...@@ -128,6 +141,7 @@ class OCRRec(hub.Module):
if __name__ == '__main__': if __name__ == '__main__':
ocr = OCRRec() ocr = OCRRec()
ocr._initialize()
image_path = [ image_path = [
'./doc/imgs_words/ch/word_1.jpg', './doc/imgs_words/ch/word_1.jpg',
'./doc/imgs_words/ch/word_2.jpg', './doc/imgs_words/ch/word_2.jpg',
......
# -*- 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 absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
......
# 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
# -*- 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 absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
...@@ -9,7 +22,7 @@ sys.path.insert(0, ".") ...@@ -9,7 +22,7 @@ sys.path.insert(0, ".")
import copy import copy
import time import time
import paddlehub
from paddlehub.common.logger import logger from paddlehub.common.logger import logger
from paddlehub.module.module import moduleinfo, runnable, serving from paddlehub.module.module import moduleinfo, runnable, serving
import cv2 import cv2
...@@ -28,7 +41,7 @@ from deploy.hubserving.ocr_system.params import read_params ...@@ -28,7 +41,7 @@ from deploy.hubserving.ocr_system.params import read_params
summary="ocr system service", summary="ocr system service",
author="paddle-dev", author="paddle-dev",
author_email="paddle-dev@baidu.com", author_email="paddle-dev@baidu.com",
type="cv/text_recognition") type="cv/PP-OCR_system")
class OCRSystem(hub.Module): class OCRSystem(hub.Module):
def _initialize(self, use_gpu=False, enable_mkldnn=False): def _initialize(self, use_gpu=False, enable_mkldnn=False):
""" """
...@@ -134,6 +147,7 @@ class OCRSystem(hub.Module): ...@@ -134,6 +147,7 @@ class OCRSystem(hub.Module):
if __name__ == '__main__': if __name__ == '__main__':
ocr = OCRSystem() ocr = OCRSystem()
ocr._initialize()
image_path = [ image_path = [
'./doc/imgs/11.jpg', './doc/imgs/11.jpg',
'./doc/imgs/12.jpg', './doc/imgs/12.jpg',
......
# -*- 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 absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
......
[English](readme_en.md) | 简体中文 [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种服务部署方式: PaddleOCR提供2种服务部署方式:
- 基于PaddleHub Serving的部署:代码路径为"`./deploy/hubserving`",按照本教程使用; - 基于PaddleHub Serving的部署:代码路径为"`./deploy/hubserving`",按照本教程使用;
- 基于PaddleServing的部署:代码路径为"`./deploy/pdserving`",使用方法参考[文档](../../deploy/pdserving/README_CN.md) - 基于PaddleServing的部署:代码路径为"`./deploy/pdserving`",使用方法参考[文档](../../deploy/pdserving/README_CN.md)
# 基于PaddleHub Serving的服务部署 # 基于PaddleHub Serving的服务部署
hubserving服务部署目录下包括检测、识别、2阶段串联三种服务包,请根据需求选择相应的服务包进行安装和启动。目录结构如下: hubserving服务部署目录下包括文本检测、文本方向分类,文本识别、文本检测+文本方向分类+文本识别3阶段串联,表格识别和PP-Structure六种服务包,请根据需求选择相应的服务包进行安装和启动。目录结构如下:
``` ```
deploy/hubserving/ deploy/hubserving/
└─ ocr_cls 分类模块服务包 └─ ocr_cls 文本方向分类模块服务包
└─ ocr_det 检测模块服务包 └─ ocr_det 文本检测模块服务包
└─ ocr_rec 识别模块服务包 └─ ocr_rec 文本识别模块服务包
└─ ocr_system 检测+识别串联服务包 └─ ocr_system 文本检测+文本方向分类+文本识别串联服务包
└─ structure_table 表格识别服务包
└─ structure_system PP-Structure服务包
``` ```
每个服务包下包含3个文件。以2阶段串联服务包为例,目录如下: 每个服务包下包含3个文件。以2阶段串联服务包为例,目录如下:
...@@ -23,28 +39,32 @@ deploy/hubserving/ocr_system/ ...@@ -23,28 +39,32 @@ deploy/hubserving/ocr_system/
└─ module.py 主模块,必选,包含服务的完整逻辑 └─ module.py 主模块,必选,包含服务的完整逻辑
└─ params.py 参数文件,必选,包含模型路径、前后处理参数等参数 └─ params.py 参数文件,必选,包含模型路径、前后处理参数等参数
``` ```
## 1. 近期更新
## 快速启动服务 * 2022.03.30 新增PP-Structure和表格识别两种服务。
## 2. 快速启动服务
以下步骤以检测+识别2阶段串联服务为例,如果只需要检测服务或识别服务,替换相应文件路径即可。 以下步骤以检测+识别2阶段串联服务为例,如果只需要检测服务或识别服务,替换相应文件路径即可。
### 1. 准备环境 ### 2.1 准备环境
```shell ```shell
# 安装paddlehub # 安装paddlehub
# paddlehub 需要 python>3.6.2 # 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模型,默认模型路径为: 安装服务模块前,需要准备推理模型并放到正确路径。默认使用的是PP-OCRv2模型,默认模型路径为:
``` ```
检测模型:./inference/ch_PP-OCRv2_det_infer/ 检测模型:./inference/ch_PP-OCRv2_det_infer/
识别模型:./inference/ch_PP-OCRv2_rec_infer/ 识别模型:./inference/ch_PP-OCRv2_rec_infer/
方向分类器:./inference/ch_ppocr_mobile_v2.0_cls_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. 安装服务模块 ### 2.3 安装服务模块
PaddleOCR提供3种服务模块,根据需要安装所需模块。 PaddleOCR提供5种服务模块,根据需要安装所需模块。
* 在Linux环境下,安装示例如下: * 在Linux环境下,安装示例如下:
```shell ```shell
...@@ -59,6 +79,12 @@ hub install deploy/hubserving/ocr_rec/ ...@@ -59,6 +79,12 @@ hub install deploy/hubserving/ocr_rec/
# 或,安装检测+识别串联服务模块: # 或,安装检测+识别串联服务模块:
hub install deploy/hubserving/ocr_system/ hub install deploy/hubserving/ocr_system/
# 或,安装表格识别服务模块:
hub install deploy/hubserving/structure_table/
# 或,安装PP-Structure服务模块:
hub install deploy/hubserving/structure_system/
``` ```
* 在Windows环境下(文件夹的分隔符为`\`),安装示例如下: * 在Windows环境下(文件夹的分隔符为`\`),安装示例如下:
...@@ -74,10 +100,16 @@ hub install deploy\hubserving\ocr_rec\ ...@@ -74,10 +100,16 @@ hub install deploy\hubserving\ocr_rec\
# 或,安装检测+识别串联服务模块: # 或,安装检测+识别串联服务模块:
hub install deploy\hubserving\ocr_system\ hub install deploy\hubserving\ocr_system\
# 或,安装表格识别服务模块:
hub install deploy\hubserving\structure_table\
# 或,安装PP-Structure服务模块:
hub install deploy\hubserving\structure_system\
``` ```
### 4. 启动服务 ### 2.4 启动服务
#### 方式1. 命令行命令启动(仅支持CPU) #### 2.4.1. 命令行命令启动(仅支持CPU)
**启动命令:** **启动命令:**
```shell ```shell
$ hub serving start --modules [Module1==Version1, Module2==Version2, ...] \ $ hub serving start --modules [Module1==Version1, Module2==Version2, ...] \
...@@ -89,7 +121,7 @@ $ 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键值对的形式列出<br>*`当不指定Version时,默认选择最新版本`*| |--modules/-m|PaddleHub Serving预安装模型,以多个Module==Version键值对的形式列出<br>*`当不指定Version时,默认选择最新版本`*|
|--port/-p|服务端口,默认为8866| |--port/-p|服务端口,默认为8866|
|--use_multiprocess|是否启用并发方式,默认为单进程方式,推荐多核CPU机器使用此方式<br>*`Windows操作系统只支持单进程方式`*| |--use_multiprocess|是否启用并发方式,默认为单进程方式,推荐多核CPU机器使用此方式<br>*`Windows操作系统只支持单进程方式`*|
...@@ -99,7 +131,7 @@ $ hub serving start --modules [Module1==Version1, Module2==Version2, ...] \ ...@@ -99,7 +131,7 @@ $ hub serving start --modules [Module1==Version1, Module2==Version2, ...] \
这样就完成了一个服务化API的部署,使用默认端口号8866。 这样就完成了一个服务化API的部署,使用默认端口号8866。
#### 方式2. 配置文件启动(支持CPU、GPU) #### 2.4.2 配置文件启动(支持CPU、GPU)
**启动命令:** **启动命令:**
```hub serving start -c config.json``` ```hub serving start -c config.json```
...@@ -136,7 +168,7 @@ export CUDA_VISIBLE_DEVICES=3 ...@@ -136,7 +168,7 @@ export CUDA_VISIBLE_DEVICES=3
hub serving start -c deploy/hubserving/ocr_system/config.json hub serving start -c deploy/hubserving/ocr_system/config.json
``` ```
## 发送预测请求 ## 3. 发送预测请求
配置好服务端,可使用以下命令发送预测请求,获取预测结果: 配置好服务端,可使用以下命令发送预测请求,获取预测结果:
```python tools/test_hubserving.py server_url image_path``` ```python tools/test_hubserving.py server_url image_path```
...@@ -144,38 +176,46 @@ hub serving start -c deploy/hubserving/ocr_system/config.json ...@@ -144,38 +176,46 @@ hub serving start -c deploy/hubserving/ocr_system/config.json
需要给脚本传递2个参数: 需要给脚本传递2个参数:
- **server_url**:服务地址,格式为 - **server_url**:服务地址,格式为
`http://[ip_address]:[port]/predict/[module_name]` `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:8865/predict/ocr_det`
`http://127.0.0.1:8866/predict/ocr_cls` `http://127.0.0.1:8866/predict/ocr_cls`
`http://127.0.0.1:8867/predict/ocr_rec` `http://127.0.0.1:8867/predict/ocr_rec`
`http://127.0.0.1:8868/predict/ocr_system` `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种字段,信息如下: 返回结果为列表(list),列表中的每一项为词典(dict),词典一共可能包含3种字段,信息如下:
|字段名称|数据类型|意义| |字段名称|数据类型|意义|
|----|----|----| |---|---|---|
|angle|str|文本角度| |angle|str|文本角度|
|text|str|文本内容| |text|str|文本内容|
|confidence|float| 文本识别置信度或文本角度分类置信度| |confidence|float| 文本识别置信度或文本角度分类置信度|
|text_region|list|文本位置坐标| |text_region|list|文本位置坐标|
|html|str|表格的html字符串|
|regions|list|版面分析+表格识别+OCR的结果,每一项为一个list,包含表示区域坐标的`bbox`,区域类型的`type`和区域结果的`res`三个字段|
不同模块返回的字段不同,如,文本识别服务模块返回结果不含`text_region`字段,具体信息如下: 不同模块返回的字段不同,如,文本识别服务模块返回结果不含`text_region`字段,具体信息如下:
| 字段名/模块名 | ocr_det | ocr_cls | ocr_rec | ocr_system | | 字段名/模块名 | ocr_det | ocr_cls | ocr_rec | ocr_system | structure_table | structure_system |
| ---- | ---- | ---- | ---- | ---- | | --- | --- | --- | --- | --- | --- |--- |
|angle| | ✔ | | ✔ | |angle| | ✔ | | ✔ | ||
|text| | |✔|✔| |text| | |✔|✔| | ✔ |
|confidence| |✔ |✔|✔| |confidence| |✔ |✔| | | ✔|
|text_region| ✔| | |✔ | |text_region| ✔| | |✔ | | ✔|
|html| | | | |✔ |✔|
|regions| | | | |✔ |✔ |
**说明:** 如果需要增加、删除、修改返回字段,可在相应模块的`module.py`文件中进行修改,完整流程参考下一节自定义修改服务模块。 **说明:** 如果需要增加、删除、修改返回字段,可在相应模块的`module.py`文件中进行修改,完整流程参考下一节自定义修改服务模块。
## 自定义修改服务模块 ## 5. 自定义修改服务模块
如果需要修改服务逻辑,你一般需要操作以下步骤(以修改`ocr_system`为例): 如果需要修改服务逻辑,你一般需要操作以下步骤(以修改`ocr_system`为例):
- 1、 停止服务 - 1、 停止服务
......
English | [简体中文](readme.md) 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: PaddleOCR provides 2 service deployment methods:
- Based on **PaddleHub Serving**: Code path is "`./deploy/hubserving`". Please follow this tutorial. - 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. - 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 # 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/ deploy/hubserving/
└─ ocr_det detection module service package └─ ocr_det text detection module service package
└─ ocr_cls angle class module service package └─ ocr_cls text angle class module service package
└─ ocr_rec recognition module service package └─ ocr_rec text recognition module service package
└─ ocr_system two-stage series connection 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: 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/ ...@@ -23,43 +39,54 @@ deploy/hubserving/ocr_system/
└─ module.py Main module file, required, contains the complete logic of the service └─ 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 └─ 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. 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 ```shell
# Install paddlehub # Install paddlehub
# python>3.6.2 is required bt paddlehub # python>3.6.2 is required bt paddlehub
pip3 install paddlehub==2.1.0 --upgrade -i https://pypi.tuna.tsinghua.edu.cn/simple 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: 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/ text detection model: ./inference/ch_PP-OCRv2_det_infer/
recognition model: ./inference/ch_PP-OCRv2_rec_infer/ text recognition model: ./inference/ch_PP-OCRv2_rec_infer/
text direction classifier: ./inference/ch_ppocr_mobile_v2.0_cls_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. **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 ### 2.3 Install Service Module
PaddleOCR provides 3 kinds of service modules, install the required modules according to your needs. PaddleOCR provides 5 kinds of service modules, install the required modules according to your needs.
* On Linux platform, the examples are as follows. * On Linux platform, the examples are as follows.
```shell ```shell
# Install the detection service module: # Install the text detection service module:
hub install deploy/hubserving/ocr_det/ 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/ 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/ hub install deploy/hubserving/ocr_rec/
# Or, install the 2-stage series service module: # Or, install the 2-stage series service module:
hub install deploy/hubserving/ocr_system/ 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. * On Windows platform, the examples are as follows.
...@@ -75,10 +102,16 @@ hub install deploy\hubserving\ocr_rec\ ...@@ -75,10 +102,16 @@ hub install deploy\hubserving\ocr_rec\
# Or, install the 2-stage series service module: # Or, install the 2-stage series service module:
hub install deploy\hubserving\ocr_system\ 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 ### 2.4 Start service
#### Way 1. Start with command line parameters (CPU only) #### 2.4.1 Start with command line parameters (CPU only)
**start command:** **start command:**
```shell ```shell
...@@ -90,7 +123,7 @@ $ hub serving start --modules [Module1==Version1, Module2==Version2, ...] \ ...@@ -90,7 +123,7 @@ $ hub serving start --modules [Module1==Version1, Module2==Version2, ...] \
**parameters:** **parameters:**
|parameters|usage| |parameters|usage|
|-|-| |---|---|
|--modules/-m|PaddleHub Serving pre-installed model, listed in the form of multiple Module==Version key-value pairs<br>*`When Version is not specified, the latest version is selected by default`*| |--modules/-m|PaddleHub Serving pre-installed model, listed in the form of multiple Module==Version key-value pairs<br>*`When Version is not specified, the latest version is selected by default`*|
|--port/-p|Service port, default is 8866| |--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<br>*`Windows operating system only supports single-process mode`*| |--use_multiprocess|Enable concurrent mode, the default is single-process mode, this mode is recommended for multi-core CPU machines<br>*`Windows operating system only supports single-process mode`*|
...@@ -103,7 +136,7 @@ hub serving start -m ocr_system ...@@ -103,7 +136,7 @@ hub serving start -m ocr_system
This completes the deployment of a service API, using the default port number 8866. 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:** **start command:**
```shell ```shell
hub serving start --config/-c config.json hub serving start --config/-c config.json
...@@ -140,7 +173,7 @@ export CUDA_VISIBLE_DEVICES=3 ...@@ -140,7 +173,7 @@ export CUDA_VISIBLE_DEVICES=3
hub serving start -c deploy/hubserving/ocr_system/config.json 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: After the service starts, you can use the following command to send a prediction request to obtain the prediction result:
```shell ```shell
python tools/test_hubserving.py server_url image_path python tools/test_hubserving.py server_url image_path
...@@ -149,19 +182,24 @@ 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: Two parameters need to be passed to the script:
- **server_url**:service address,format of which is - **server_url**:service address,format of which is
`http://[ip_address]:[port]/predict/[module_name]` `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:8865/predict/ocr_det`
`http://127.0.0.1:8866/predict/ocr_cls` `http://127.0.0.1:8866/predict/ocr_cls`
`http://127.0.0.1:8867/predict/ocr_rec` `http://127.0.0.1:8867/predict/ocr_rec`
`http://127.0.0.1:8868/predict/ocr_system` `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.** **Eg.**
```shell ```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: 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| |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 ...@@ -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| |text|str|text content|
|confidence|float|text recognition confidence| |confidence|float|text recognition confidence|
|text_region|list|text location coordinates| |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: 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 | | field name/module name | ocr_det | ocr_cls | ocr_rec | ocr_system | structure_table | structure_system |
| ---- | ---- | ---- | ---- | ---- | | --- | --- | --- | --- | --- | --- |--- |
|angle| | ✔ | | ✔ | |angle| | ✔ | | ✔ | ||
|text| | |✔|✔| |text| | |✔|✔| | ✔ |
|confidence| |✔ |✔|✔| |confidence| |✔ |✔| | | ✔|
|text_region| ✔| | |✔ | |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. **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): 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 - 1. Stop service
......
# 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
{
"modules_info": {
"structure_system": {
"init_args": {
"version": "1.0.0",
"use_gpu": true
},
"predict_args": {
}
}
},
"port": 8870,
"use_multiprocess": false,
"workers": 2
}
# 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)
# 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
# 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
{
"modules_info": {
"structure_table": {
"init_args": {
"version": "1.0.0",
"use_gpu": true
},
"predict_args": {
}
}
},
"port": 8869,
"use_multiprocess": false,
"workers": 2
}
# 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)
# 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
...@@ -39,7 +39,7 @@ from ppocr.utils.utility import check_and_read_gif, get_image_file_list ...@@ -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 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 tools.infer.utility import draw_ocr, str2bool, check_gpu
from ppstructure.utility import init_args, draw_structure_result 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__ = [ __all__ = [
'PaddleOCR', 'PPStructure', 'draw_ocr', 'draw_structure_result', 'PaddleOCR', 'PPStructure', 'draw_ocr', 'draw_structure_result',
...@@ -398,7 +398,7 @@ class PaddleOCR(predict_system.TextSystem): ...@@ -398,7 +398,7 @@ class PaddleOCR(predict_system.TextSystem):
return rec_res return rec_res
class PPStructure(OCRSystem): class PPStructure(StructureSystem):
def __init__(self, **kwargs): def __init__(self, **kwargs):
params = parse_args(mMain=False) params = parse_args(mMain=False)
params.__dict__.update(**kwargs) params.__dict__.update(**kwargs)
......
...@@ -22,6 +22,7 @@ sys.path.append(os.path.abspath(os.path.join(__dir__, '..'))) ...@@ -22,6 +22,7 @@ sys.path.append(os.path.abspath(os.path.join(__dir__, '..')))
os.environ["FLAGS_allocator_strategy"] = 'auto_growth' os.environ["FLAGS_allocator_strategy"] = 'auto_growth'
import cv2 import cv2
import json
import numpy as np import numpy as np
import time import time
import logging import logging
...@@ -35,7 +36,7 @@ from ppstructure.utility import parse_args, draw_structure_result ...@@ -35,7 +36,7 @@ from ppstructure.utility import parse_args, draw_structure_result
logger = get_logger() logger = get_logger()
class OCRSystem(object): class StructureSystem(object):
def __init__(self, args): def __init__(self, args):
self.mode = args.mode self.mode = args.mode
if self.mode == 'structure': if self.mode == 'structure':
...@@ -66,8 +67,7 @@ class OCRSystem(object): ...@@ -66,8 +67,7 @@ class OCRSystem(object):
self.use_angle_cls = args.use_angle_cls self.use_angle_cls = args.use_angle_cls
self.drop_score = args.drop_score self.drop_score = args.drop_score
elif self.mode == 'vqa': elif self.mode == 'vqa':
from ppstructure.vqa.infer_ser_e2e import SerPredictor, draw_ser_results raise NotImplementedError
self.vqa_engine = SerPredictor(args)
def __call__(self, img): def __call__(self, img):
if self.mode == 'structure': if self.mode == 'structure':
...@@ -82,24 +82,24 @@ class OCRSystem(object): ...@@ -82,24 +82,24 @@ class OCRSystem(object):
res = self.table_system(roi_img) res = self.table_system(roi_img)
else: else:
filter_boxes, filter_rec_res = self.text_system(roi_img) 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 # remove style char
style_token = [ style_token = [
'<strike>', '<strike>', '<sup>', '</sub>', '<b>', '<strike>', '<strike>', '<sup>', '</sub>', '<b>',
'</b>', '<sub>', '</sup>', '<overline>', '</overline>', '</b>', '<sub>', '</sup>', '<overline>', '</overline>',
'<underline>', '</underline>', '<i>', '</i>' '<underline>', '</underline>', '<i>', '</i>'
] ]
filter_rec_res_tmp = [] res = []
for rec_res in filter_rec_res: for box, rec_res in zip(filter_boxes, filter_rec_res):
rec_str, rec_conf = rec_res rec_str, rec_conf = rec_res
for token in style_token: for token in style_token:
if token in rec_str: if token in rec_str:
rec_str = rec_str.replace(token, '') rec_str = rec_str.replace(token, '')
filter_rec_res_tmp.append((rec_str, rec_conf)) box += [x1, y1]
res = (filter_boxes, filter_rec_res_tmp) res.append({
'text': rec_str,
'confidence': float(rec_conf),
'text_region': box.tolist()
})
res_list.append({ res_list.append({
'type': region.type, 'type': region.type,
'bbox': [x1, y1, x2, y2], 'bbox': [x1, y1, x2, y2],
...@@ -107,7 +107,7 @@ class OCRSystem(object): ...@@ -107,7 +107,7 @@ class OCRSystem(object):
'res': res 'res': res
}) })
elif self.mode == 'vqa': elif self.mode == 'vqa':
res_list, _ = self.vqa_engine(img) raise NotImplementedError
return res_list return res_list
...@@ -123,15 +123,14 @@ def save_structure_res(res, save_folder, img_name): ...@@ -123,15 +123,14 @@ def save_structure_res(res, save_folder, img_name):
excel_path = os.path.join(excel_save_folder, excel_path = os.path.join(excel_save_folder,
'{}.xlsx'.format(region['bbox'])) '{}.xlsx'.format(region['bbox']))
to_excel(region['res'], excel_path) to_excel(region['res'], excel_path)
if region['type'] == 'Figure': elif region['type'] == 'Figure':
roi_img = region['img'] roi_img = region['img']
img_path = os.path.join(excel_save_folder, img_path = os.path.join(excel_save_folder,
'{}.jpg'.format(region['bbox'])) '{}.jpg'.format(region['bbox']))
cv2.imwrite(img_path, roi_img) cv2.imwrite(img_path, roi_img)
else: else:
for box, rec_res in zip(region['res'][0], region['res'][1]): for text_result in region['res']:
f.write('{}\t{}\n'.format( f.write('{}\n'.format(json.dumps(text_result)))
np.array(box).reshape(-1).tolist(), rec_res))
def main(args): def main(args):
...@@ -139,7 +138,7 @@ def main(args): ...@@ -139,7 +138,7 @@ def main(args):
image_file_list = image_file_list image_file_list = image_file_list
image_file_list = image_file_list[args.process_id::args.total_process_num] 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) img_num = len(image_file_list)
save_folder = os.path.join(args.output, structure_sys.mode) save_folder = os.path.join(args.output, structure_sys.mode)
os.makedirs(save_folder, exist_ok=True) os.makedirs(save_folder, exist_ok=True)
...@@ -162,8 +161,9 @@ def main(args): ...@@ -162,8 +161,9 @@ def main(args):
draw_img = draw_structure_result(img, res, args.vis_font_path) draw_img = draw_structure_result(img, res, args.vis_font_path)
img_save_path = os.path.join(save_folder, img_name, 'show.jpg') img_save_path = os.path.join(save_folder, img_name, 'show.jpg')
elif structure_sys.mode == 'vqa': elif structure_sys.mode == 'vqa':
draw_img = draw_ser_results(img, res, args.vis_font_path) raise NotImplementedError
img_save_path = os.path.join(save_folder, img_name + '.jpg') # 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) cv2.imwrite(img_save_path, draw_img)
logger.info('result save to {}'.format(img_save_path)) logger.info('result save to {}'.format(img_save_path))
elapse = time.time() - starttime elapse = time.time() - starttime
......
...@@ -40,12 +40,6 @@ def init_args(): ...@@ -40,12 +40,6 @@ def init_args():
type=ast.literal_eval, type=ast.literal_eval,
default=None, default=None,
help='label map according to ppstructure/layout/README_ch.md') 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( parser.add_argument(
"--mode", "--mode",
type=str, type=str,
...@@ -67,10 +61,10 @@ def draw_structure_result(image, result, font_path): ...@@ -67,10 +61,10 @@ def draw_structure_result(image, result, font_path):
if region['type'] == 'Table': if region['type'] == 'Table':
pass pass
else: else:
for box, rec_res in zip(region['res'][0], region['res'][1]): for text_result in region['res']:
boxes.append(np.array(box).reshape(-1, 2)) boxes.append(np.array(text_result['text_region']))
txts.append(rec_res[0]) txts.append(text_result['text'])
scores.append(rec_res[1]) scores.append(text_result['confidence'])
im_show = draw_ocr_box_txt( im_show = draw_ocr_box_txt(
image, boxes, txts, scores, font_path=font_path, drop_score=0) image, boxes, txts, scores, font_path=font_path, drop_score=0)
return im_show return im_show
...@@ -25,7 +25,9 @@ import numpy as np ...@@ -25,7 +25,9 @@ import numpy as np
import time import time
from PIL import Image from PIL import Image
from ppocr.utils.utility import get_image_file_list 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 requests
import json import json
...@@ -69,8 +71,33 @@ def draw_server_result(image_file, res): ...@@ -69,8 +71,33 @@ def draw_server_result(image_file, res):
return draw_img return draw_img
def main(url, image_path): def save_structure_res(res, save_folder, image_file):
image_file_list = get_image_file_list(image_path) 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 is_visualize = False
headers = {"Content-type": "application/json"} headers = {"Content-type": "application/json"}
cnt = 0 cnt = 0
...@@ -80,38 +107,51 @@ def main(url, image_path): ...@@ -80,38 +107,51 @@ def main(url, image_path):
if img is None: if img is None:
logger.info("error in loading image:{}".format(image_file)) logger.info("error in loading image:{}".format(image_file))
continue continue
img_name = os.path.basename(image_file)
# 发送HTTP请求 # seed http request
starttime = time.time() starttime = time.time()
data = {'images': [cv2_to_base64(img)]} 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 elapse = time.time() - starttime
total_time += elapse total_time += elapse
logger.info("Predict time of %s: %.3fs" % (image_file, elapse)) logger.info("Predict time of %s: %.3fs" % (image_file, elapse))
res = r.json()["results"][0] res = r.json()["results"][0]
logger.info(res) logger.info(res)
if is_visualize: if args.visualize:
draw_img = draw_server_result(image_file, res) 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: if draw_img is not None:
draw_img_save = "./server_results/" if not os.path.exists(args.output):
if not os.path.exists(draw_img_save): os.makedirs(args.output)
os.makedirs(draw_img_save)
cv2.imwrite( 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]) draw_img[:, :, ::-1])
logger.info("The visualized image saved in {}".format( 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 cnt += 1
if cnt % 100 == 0: if cnt % 100 == 0:
logger.info("{} processed".format(cnt)) logger.info("{} processed".format(cnt))
logger.info("avg time cost: {}".format(float(total_time) / 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 __name__ == '__main__':
if len(sys.argv) != 3: args = parse_args()
logger.info("Usage: %s server_url image_path" % sys.argv[0]) main(args)
else:
server_url = sys.argv[1]
image_path = sys.argv[2]
main(server_url, image_path)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册