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)