From 0975906eeca00f0e95274c34741c3ca12f8f2a9c Mon Sep 17 00:00:00 2001 From: dyning Date: Mon, 20 Jul 2020 20:24:51 +0800 Subject: [PATCH 01/26] Update README_cn.md --- README_cn.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README_cn.md b/README_cn.md index 1594b6b2..f5914f2b 100644 --- a/README_cn.md +++ b/README_cn.md @@ -3,7 +3,8 @@ ## 简介 PaddleOCR旨在打造一套丰富、领先、且实用的OCR工具库,助力使用者训练出更好的模型,并应用落地。 -**直播预告:2020年7月21日晚8点B站直播,PaddleOCR开源大礼包全面解读,直播地址当天更新** +**直播预告:2020年7月21日晚8点B站直播,PaddleOCR开源大礼包全面解读** +直播地址:https://live.bilibili.com/21689802 **近期更新** - 2020.7.15 添加基于EasyEdge和Paddle-Lite的移动端DEMO,支持iOS和Android系统 From 034f76709a25f003e0767b8a7458dbad400cda48 Mon Sep 17 00:00:00 2001 From: dyning Date: Mon, 20 Jul 2020 20:25:06 +0800 Subject: [PATCH 02/26] Update README_cn.md --- README_cn.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README_cn.md b/README_cn.md index f5914f2b..7b3c3fec 100644 --- a/README_cn.md +++ b/README_cn.md @@ -4,6 +4,7 @@ PaddleOCR旨在打造一套丰富、领先、且实用的OCR工具库,助力使用者训练出更好的模型,并应用落地。 **直播预告:2020年7月21日晚8点B站直播,PaddleOCR开源大礼包全面解读** + 直播地址:https://live.bilibili.com/21689802 **近期更新** From a3494c66e95f0505c86d0b1a3f1b70056a4dca36 Mon Sep 17 00:00:00 2001 From: dyning Date: Mon, 20 Jul 2020 20:26:02 +0800 Subject: [PATCH 03/26] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 26ecef77..60ea75b7 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ PaddleOCR aims to create rich, leading, and practical OCR tools that help users **Live stream on coming day**: July 21, 2020 at 8 pm BiliBili station live stream +Live address:https://live.bilibili.com/h5/21689802 + **Recent updates** - 2020.7.15, Add mobile App demo , support both iOS and Android ( based on easyedge and Paddle Lite) From d07a223df83267d59ae6f3a97671656b8e44ca72 Mon Sep 17 00:00:00 2001 From: wangjiawei04 Date: Mon, 20 Jul 2020 21:15:45 +0800 Subject: [PATCH 04/26] add pdserving ocr --- deploy/pdserving/det_local_server.py | 71 ++++++++++++++++++ deploy/pdserving/det_web_server.py | 72 +++++++++++++++++++ deploy/pdserving/ocr_local_server.py | 103 +++++++++++++++++++++++++++ deploy/pdserving/ocr_web_client.py | 37 ++++++++++ deploy/pdserving/ocr_web_server.py | 99 +++++++++++++++++++++++++ deploy/pdserving/readme.md | 55 +++++++++++++- deploy/pdserving/rec_local_server.py | 72 +++++++++++++++++++ deploy/pdserving/rec_web_server.py | 71 ++++++++++++++++++ 8 files changed, 578 insertions(+), 2 deletions(-) create mode 100644 deploy/pdserving/det_local_server.py create mode 100644 deploy/pdserving/det_web_server.py create mode 100644 deploy/pdserving/ocr_local_server.py create mode 100644 deploy/pdserving/ocr_web_client.py create mode 100644 deploy/pdserving/ocr_web_server.py create mode 100644 deploy/pdserving/rec_local_server.py create mode 100644 deploy/pdserving/rec_web_server.py diff --git a/deploy/pdserving/det_local_server.py b/deploy/pdserving/det_local_server.py new file mode 100644 index 00000000..acfccdb6 --- /dev/null +++ b/deploy/pdserving/det_local_server.py @@ -0,0 +1,71 @@ +# Copyright (c) 2020 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 paddle_serving_client import Client +import cv2 +import sys +import numpy as np +import os +from paddle_serving_client import Client +from paddle_serving_app.reader import Sequential, ResizeByFactor +from paddle_serving_app.reader import Div, Normalize, Transpose +from paddle_serving_app.reader import DBPostProcess, FilterBoxes +from paddle_serving_server_gpu.web_service import WebService +import time +import re +import base64 + + +class OCRService(WebService): + def init_det(self): + self.det_preprocess = Sequential([ + ResizeByFactor(32, 960), Div(255), + Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), Transpose( + (2, 0, 1)) + ]) + self.filter_func = FilterBoxes(10, 10) + self.post_func = DBPostProcess({ + "thresh": 0.3, + "box_thresh": 0.5, + "max_candidates": 1000, + "unclip_ratio": 1.5, + "min_size": 3 + }) + + def preprocess(self, feed=[], fetch=[]): + data = base64.b64decode(feed[0]["image"].encode('utf8')) + data = np.fromstring(data, np.uint8) + im = cv2.imdecode(data, cv2.IMREAD_COLOR) + self.ori_h, self.ori_w, _ = im.shape + det_img = self.det_preprocess(im) + _, self.new_h, self.new_w = det_img.shape + return {"image": det_img[np.newaxis, :].copy()}, ["concat_1.tmp_0"] + + def postprocess(self, feed={}, fetch=[], fetch_map=None): + det_out = fetch_map["concat_1.tmp_0"] + ratio_list = [ + float(self.new_h) / self.ori_h, float(self.new_w) / self.ori_w + ] + dt_boxes_list = self.post_func(det_out, [ratio_list]) + dt_boxes = self.filter_func(dt_boxes_list[0], [self.ori_h, self.ori_w]) + return {"dt_boxes": dt_boxes.tolist()} + + +ocr_service = OCRService(name="ocr") +ocr_service.load_model_config("ocr_det_model") +ocr_service.set_gpus("0") +ocr_service.prepare_server(workdir="workdir", port=9292, device="gpu", gpuid=0) +ocr_service.init_det() +ocr_service.run_debugger_service() +ocr_service.run_web_service() diff --git a/deploy/pdserving/det_web_server.py b/deploy/pdserving/det_web_server.py new file mode 100644 index 00000000..dd69be0c --- /dev/null +++ b/deploy/pdserving/det_web_server.py @@ -0,0 +1,72 @@ +# Copyright (c) 2020 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 paddle_serving_client import Client +import cv2 +import sys +import numpy as np +import os +from paddle_serving_client import Client +from paddle_serving_app.reader import Sequential, ResizeByFactor +from paddle_serving_app.reader import Div, Normalize, Transpose +from paddle_serving_app.reader import DBPostProcess, FilterBoxes +from paddle_serving_server_gpu.web_service import WebService +import time +import re +import base64 + + +class OCRService(WebService): + def init_det(self): + self.det_preprocess = Sequential([ + ResizeByFactor(32, 960), Div(255), + Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), Transpose( + (2, 0, 1)) + ]) + self.filter_func = FilterBoxes(10, 10) + self.post_func = DBPostProcess({ + "thresh": 0.3, + "box_thresh": 0.5, + "max_candidates": 1000, + "unclip_ratio": 1.5, + "min_size": 3 + }) + + def preprocess(self, feed=[], fetch=[]): + data = base64.b64decode(feed[0]["image"].encode('utf8')) + data = np.fromstring(data, np.uint8) + im = cv2.imdecode(data, cv2.IMREAD_COLOR) + self.ori_h, self.ori_w, _ = im.shape + det_img = self.det_preprocess(im) + _, self.new_h, self.new_w = det_img.shape + print(det_img) + return {"image": det_img}, ["concat_1.tmp_0"] + + def postprocess(self, feed={}, fetch=[], fetch_map=None): + det_out = fetch_map["concat_1.tmp_0"] + ratio_list = [ + float(self.new_h) / self.ori_h, float(self.new_w) / self.ori_w + ] + dt_boxes_list = self.post_func(det_out, [ratio_list]) + dt_boxes = self.filter_func(dt_boxes_list[0], [self.ori_h, self.ori_w]) + return {"dt_boxes": dt_boxes.tolist()} + + +ocr_service = OCRService(name="ocr") +ocr_service.load_model_config("ocr_det_model") +ocr_service.set_gpus("0") +ocr_service.prepare_server(workdir="workdir", port=9292, device="gpu", gpuid=0) +ocr_service.init_det() +ocr_service.run_rpc_service() +ocr_service.run_web_service() diff --git a/deploy/pdserving/ocr_local_server.py b/deploy/pdserving/ocr_local_server.py new file mode 100644 index 00000000..93e2d7a3 --- /dev/null +++ b/deploy/pdserving/ocr_local_server.py @@ -0,0 +1,103 @@ +# Copyright (c) 2020 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 paddle_serving_client import Client +from paddle_serving_app.reader import OCRReader +import cv2 +import sys +import numpy as np +import os +from paddle_serving_client import Client +from paddle_serving_app.reader import Sequential, URL2Image, ResizeByFactor +from paddle_serving_app.reader import Div, Normalize, Transpose +from paddle_serving_app.reader import DBPostProcess, FilterBoxes, GetRotateCropImage, SortedBoxes +from paddle_serving_server_gpu.web_service import WebService +from paddle_serving_app.local_predict import Debugger +import time +import re +import base64 + + +class OCRService(WebService): + def init_det_debugger(self, det_model_config): + self.det_preprocess = Sequential([ + ResizeByFactor(32, 960), Div(255), + Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), Transpose( + (2, 0, 1)) + ]) + self.det_client = Debugger() + self.det_client.load_model_config( + det_model_config, gpu=True, profile=False) + self.ocr_reader = OCRReader() + + def preprocess(self, feed=[], fetch=[]): + data = base64.b64decode(feed[0]["image"].encode('utf8')) + data = np.fromstring(data, np.uint8) + im = cv2.imdecode(data, cv2.IMREAD_COLOR) + ori_h, ori_w, _ = im.shape + det_img = self.det_preprocess(im) + _, new_h, new_w = det_img.shape + det_img = det_img[np.newaxis, :] + det_img = det_img.copy() + det_out = self.det_client.predict( + feed={"image": det_img}, fetch=["concat_1.tmp_0"]) + filter_func = FilterBoxes(10, 10) + post_func = DBPostProcess({ + "thresh": 0.3, + "box_thresh": 0.5, + "max_candidates": 1000, + "unclip_ratio": 1.5, + "min_size": 3 + }) + sorted_boxes = SortedBoxes() + ratio_list = [float(new_h) / ori_h, float(new_w) / ori_w] + dt_boxes_list = post_func(det_out["concat_1.tmp_0"], [ratio_list]) + dt_boxes = filter_func(dt_boxes_list[0], [ori_h, ori_w]) + dt_boxes = sorted_boxes(dt_boxes) + get_rotate_crop_image = GetRotateCropImage() + img_list = [] + max_wh_ratio = 0 + for i, dtbox in enumerate(dt_boxes): + boximg = get_rotate_crop_image(im, dt_boxes[i]) + img_list.append(boximg) + h, w = boximg.shape[0:2] + wh_ratio = w * 1.0 / h + max_wh_ratio = max(max_wh_ratio, wh_ratio) + if len(img_list) == 0: + return [], [] + _, w, h = self.ocr_reader.resize_norm_img(img_list[0], + max_wh_ratio).shape + imgs = np.zeros((len(img_list), 3, w, h)).astype('float32') + for id, img in enumerate(img_list): + norm_img = self.ocr_reader.resize_norm_img(img, max_wh_ratio) + imgs[id] = norm_img + feed = {"image": imgs.copy()} + fetch = ["ctc_greedy_decoder_0.tmp_0", "softmax_0.tmp_0"] + return feed, fetch + + def postprocess(self, feed={}, fetch=[], fetch_map=None): + rec_res = self.ocr_reader.postprocess(fetch_map, with_score=True) + res_lst = [] + for res in rec_res: + res_lst.append(res[0]) + res = {"res": res_lst} + return res + + +ocr_service = OCRService(name="ocr") +ocr_service.load_model_config("ocr_rec_model") +ocr_service.prepare_server(workdir="workdir", port=9292) +ocr_service.init_det_debugger(det_model_config="ocr_det_model") +ocr_service.run_debugger_service(gpu=True) +ocr_service.run_web_service() diff --git a/deploy/pdserving/ocr_web_client.py b/deploy/pdserving/ocr_web_client.py new file mode 100644 index 00000000..e2a92eb8 --- /dev/null +++ b/deploy/pdserving/ocr_web_client.py @@ -0,0 +1,37 @@ +# Copyright (c) 2020 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. +# -*- coding: utf-8 -*- + +import requests +import json +import cv2 +import base64 +import os, sys +import time + +def cv2_to_base64(image): + #data = cv2.imencode('.jpg', image)[1] + return base64.b64encode(image).decode( + 'utf8') #data.tostring()).decode('utf8') + +headers = {"Content-type": "application/json"} +url = "http://127.0.0.1:9292/ocr/prediction" +test_img_dir = "../../doc/imgs/" +for img_file in os.listdir(test_img_dir): + with open(os.path.join(test_img_dir, img_file), 'rb') as file: + image_data1 = file.read() + image = cv2_to_base64(image_data1) + data = {"feed": [{"image": image}], "fetch": ["res"]} + r = requests.post(url=url, headers=headers, data=json.dumps(data)) + print(r.json()) diff --git a/deploy/pdserving/ocr_web_server.py b/deploy/pdserving/ocr_web_server.py new file mode 100644 index 00000000..d017f6b9 --- /dev/null +++ b/deploy/pdserving/ocr_web_server.py @@ -0,0 +1,99 @@ +# Copyright (c) 2020 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 paddle_serving_client import Client +from paddle_serving_app.reader import OCRReader +import cv2 +import sys +import numpy as np +import os +from paddle_serving_client import Client +from paddle_serving_app.reader import Sequential, URL2Image, ResizeByFactor +from paddle_serving_app.reader import Div, Normalize, Transpose +from paddle_serving_app.reader import DBPostProcess, FilterBoxes, GetRotateCropImage, SortedBoxes +from paddle_serving_server_gpu.web_service import WebService +import time +import re +import base64 + + +class OCRService(WebService): + def init_det_client(self, det_port, det_client_config): + self.det_preprocess = Sequential([ + ResizeByFactor(32, 960), Div(255), + Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), Transpose( + (2, 0, 1)) + ]) + self.det_client = Client() + self.det_client.load_client_config(det_client_config) + self.det_client.connect(["127.0.0.1:{}".format(det_port)]) + self.ocr_reader = OCRReader() + + def preprocess(self, feed=[], fetch=[]): + data = base64.b64decode(feed[0]["image"].encode('utf8')) + data = np.fromstring(data, np.uint8) + im = cv2.imdecode(data, cv2.IMREAD_COLOR) + ori_h, ori_w, _ = im.shape + det_img = self.det_preprocess(im) + det_out = self.det_client.predict( + feed={"image": det_img}, fetch=["concat_1.tmp_0"]) + _, new_h, new_w = det_img.shape + filter_func = FilterBoxes(10, 10) + post_func = DBPostProcess({ + "thresh": 0.3, + "box_thresh": 0.5, + "max_candidates": 1000, + "unclip_ratio": 1.5, + "min_size": 3 + }) + sorted_boxes = SortedBoxes() + ratio_list = [float(new_h) / ori_h, float(new_w) / ori_w] + dt_boxes_list = post_func(det_out["concat_1.tmp_0"], [ratio_list]) + dt_boxes = filter_func(dt_boxes_list[0], [ori_h, ori_w]) + dt_boxes = sorted_boxes(dt_boxes) + get_rotate_crop_image = GetRotateCropImage() + feed_list = [] + img_list = [] + max_wh_ratio = 0 + for i, dtbox in enumerate(dt_boxes): + boximg = get_rotate_crop_image(im, dt_boxes[i]) + img_list.append(boximg) + h, w = boximg.shape[0:2] + wh_ratio = w * 1.0 / h + max_wh_ratio = max(max_wh_ratio, wh_ratio) + for img in img_list: + norm_img = self.ocr_reader.resize_norm_img(img, max_wh_ratio) + feed = {"image": norm_img} + feed_list.append(feed) + fetch = ["ctc_greedy_decoder_0.tmp_0", "softmax_0.tmp_0"] + return feed_list, fetch + + def postprocess(self, feed={}, fetch=[], fetch_map=None): + rec_res = self.ocr_reader.postprocess(fetch_map, with_score=True) + res_lst = [] + for res in rec_res: + res_lst.append(res[0]) + res = {"res": res_lst} + return res + + +ocr_service = OCRService(name="ocr") +ocr_service.load_model_config("ocr_rec_model") +ocr_service.set_gpus("0") +ocr_service.prepare_server(workdir="workdir", port=9292, device="gpu", gpuid=0) +ocr_service.init_det_client( + det_port=9293, + det_client_config="ocr_det_client/serving_client_conf.prototxt") +ocr_service.run_rpc_service() +ocr_service.run_web_service() diff --git a/deploy/pdserving/readme.md b/deploy/pdserving/readme.md index 27542774..bab44249 100644 --- a/deploy/pdserving/readme.md +++ b/deploy/pdserving/readme.md @@ -5,24 +5,75 @@ ## 快速启动服务 ### 1. 准备环境 +我们先安装Paddle Serving相关组件 +我们推荐用户使用GPU来做Paddle Serving的OCR服务部署 + +**CUDA版本:9.0以上** +**CUDNN版本:7.0以上** +**操作系统版本:CentOS 6以上** + +``` +python -m pip install paddle_serving_server_gpu paddle_serving_client paddle_serving_app +``` ### 2. 模型转换 +可以使用`paddle_serving_app`提供的模型,执行下列命令 +``` +python -m paddle_serving_app.package --get_model ocr_rec +tar -xzvf ocr_rec.tar.gz +python -m paddle_serving_app.package --get_model ocr_det +tar -xzvf ocr_det.tar.gz +``` +执行上述命令会下载`db_crnn_mobile`的模型,如果想要下载规模更大的`db_crnn_server`模型,可以在下载预测模型并解压之后。参考[如何从Paddle保存的预测模型转为Paddle Serving格式可部署的模型](https://github.com/PaddlePaddle/Serving/blob/develop/doc/INFERENCE_TO_SERVING_CN.md)。 ### 3. 启动服务 启动服务可以根据实际需求选择启动`标准版`或者`快速版`,两种方式的对比如下表: |版本|特点|适用场景| |-|-|-| -|标准版||| -|快速版||| +|标准版|稳定性高,分布式部署|适用于吞吐量大,需要跨机房部署的情况| +|快速版|部署方便,预测速度快|适用于对预测速度要求高,迭代速度快的场景| #### 方式1. 启动标准版服务 +``` +python -m paddle_serving_server_gpu.serve --model ocr_det_model --port 9293 --gpu_id 0 +python ocr_web_server.py +``` + #### 方式2. 启动快速版服务 +``` +python ocr_local_server.py +``` ## 发送预测请求 +``` +python ocr_web_client.py +``` + ## 返回结果格式说明 +返回结果是json格式 +``` +{u'result': {u'res': [u'\u571f\u5730\u6574\u6cbb\u4e0e\u571f\u58e4\u4fee\u590d\u7814\u7a76\u4e2d\u5fc3', u'\u534e\u5357\u519c\u4e1a\u5927\u5b661\u7d20\u56fe']}} +``` +我们也可以打印结果json串中`res`字段的每一句话 +``` +土地整治与土壤修复研究中心 +华南农业大学1素图 +``` + ## 自定义修改服务逻辑 + +在`ocr_web_server.py`或是`ocr_debugger_server.py`当中的`preprocess`函数里面做了检测服务和识别服务的前处理,·`postprocess`函数里面做了识别的后处理服务,可以在相应的函数中做修改。调用了`paddle_serving_app`库提供的常见CV模型的前处理/后处理库。 + +如果想要单独启动Paddle Serving的检测服务和识别服务,参见下列表格, 执行对应的脚本即可。 + +| 模型 | 标准版 | 快速版 | +| ---- | ----------------- | ------------------- | +| 检测 | det_web_server.py | det_local_server.py | +| 识别 | rec_web_server.py | rec_local_server.py | + +更多信息参见[Paddle Serving](https://github.com/PaddlePaddle/Serving) diff --git a/deploy/pdserving/rec_local_server.py b/deploy/pdserving/rec_local_server.py new file mode 100644 index 00000000..fbe67aaf --- /dev/null +++ b/deploy/pdserving/rec_local_server.py @@ -0,0 +1,72 @@ +# Copyright (c) 2020 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 paddle_serving_client import Client +from paddle_serving_app.reader import OCRReader +import cv2 +import sys +import numpy as np +import os +from paddle_serving_client import Client +from paddle_serving_app.reader import Sequential, URL2Image, ResizeByFactor +from paddle_serving_app.reader import Div, Normalize, Transpose +from paddle_serving_app.reader import DBPostProcess, FilterBoxes, GetRotateCropImage, SortedBoxes +from paddle_serving_server_gpu.web_service import WebService +import time +import re +import base64 + + +class OCRService(WebService): + def init_rec(self): + self.ocr_reader = OCRReader() + + def preprocess(self, feed=[], fetch=[]): + img_list = [] + for feed_data in feed: + data = base64.b64decode(feed_data["image"].encode('utf8')) + data = np.fromstring(data, np.uint8) + im = cv2.imdecode(data, cv2.IMREAD_COLOR) + img_list.append(im) + max_wh_ratio = 0 + for i, boximg in enumerate(img_list): + h, w = boximg.shape[0:2] + wh_ratio = w * 1.0 / h + max_wh_ratio = max(max_wh_ratio, wh_ratio) + _, w, h = self.ocr_reader.resize_norm_img(img_list[0], + max_wh_ratio).shape + imgs = np.zeros((len(img_list), 3, w, h)).astype('float32') + for i, img in enumerate(img_list): + norm_img = self.ocr_reader.resize_norm_img(img, max_wh_ratio) + imgs[i] = norm_img + feed = {"image": imgs.copy()} + fetch = ["ctc_greedy_decoder_0.tmp_0", "softmax_0.tmp_0"] + return feed, fetch + + def postprocess(self, feed={}, fetch=[], fetch_map=None): + rec_res = self.ocr_reader.postprocess(fetch_map, with_score=True) + res_lst = [] + for res in rec_res: + res_lst.append(res[0]) + res = {"res": res_lst} + return res + + +ocr_service = OCRService(name="ocr") +ocr_service.load_model_config("ocr_rec_model") +ocr_service.set_gpus("0") +ocr_service.init_rec() +ocr_service.prepare_server(workdir="workdir", port=9292, device="gpu", gpuid=0) +ocr_service.run_debugger_service() +ocr_service.run_web_service() diff --git a/deploy/pdserving/rec_web_server.py b/deploy/pdserving/rec_web_server.py new file mode 100644 index 00000000..684c313d --- /dev/null +++ b/deploy/pdserving/rec_web_server.py @@ -0,0 +1,71 @@ +# Copyright (c) 2020 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 paddle_serving_client import Client +from paddle_serving_app.reader import OCRReader +import cv2 +import sys +import numpy as np +import os +from paddle_serving_client import Client +from paddle_serving_app.reader import Sequential, URL2Image, ResizeByFactor +from paddle_serving_app.reader import Div, Normalize, Transpose +from paddle_serving_app.reader import DBPostProcess, FilterBoxes, GetRotateCropImage, SortedBoxes +from paddle_serving_server_gpu.web_service import WebService +import time +import re +import base64 + + +class OCRService(WebService): + def init_rec(self): + self.ocr_reader = OCRReader() + + def preprocess(self, feed=[], fetch=[]): + # TODO: to handle batch rec images + img_list = [] + for feed_data in feed: + data = base64.b64decode(feed_data["image"].encode('utf8')) + data = np.fromstring(data, np.uint8) + im = cv2.imdecode(data, cv2.IMREAD_COLOR) + img_list.append(im) + feed_list = [] + max_wh_ratio = 0 + for i, boximg in enumerate(img_list): + h, w = boximg.shape[0:2] + wh_ratio = w * 1.0 / h + max_wh_ratio = max(max_wh_ratio, wh_ratio) + for img in img_list: + norm_img = self.ocr_reader.resize_norm_img(img, max_wh_ratio) + feed = {"image": norm_img} + feed_list.append(feed) + fetch = ["ctc_greedy_decoder_0.tmp_0", "softmax_0.tmp_0"] + return feed_list, fetch + + def postprocess(self, feed={}, fetch=[], fetch_map=None): + rec_res = self.ocr_reader.postprocess(fetch_map, with_score=True) + res_lst = [] + for res in rec_res: + res_lst.append(res[0]) + res = {"res": res_lst} + return res + + +ocr_service = OCRService(name="ocr") +ocr_service.load_model_config("ocr_rec_model") +ocr_service.set_gpus("0") +ocr_service.init_rec() +ocr_service.prepare_server(workdir="workdir", port=9292, device="gpu", gpuid=0) +ocr_service.run_rpc_service() +ocr_service.run_web_service() From d9905dd19dfc84adbacaf995c9d791de0225c9b7 Mon Sep 17 00:00:00 2001 From: littletomatodonkey Date: Mon, 20 Jul 2020 17:23:49 +0000 Subject: [PATCH 05/26] add cpp inference for windows --- deploy/cpp_infer/CMakeLists.txt | 165 ++++++++++++++---- deploy/cpp_infer/docs/windows_vs2019_build.md | 95 ++++++++++ deploy/cpp_infer/readme.md | 3 + deploy/cpp_infer/src/config.cpp | 2 +- deploy/cpp_infer/src/utility.cpp | 22 ++- deploy/cpp_infer/tools/build.sh | 4 +- deploy/cpp_infer/tools/config.txt | 3 +- 7 files changed, 245 insertions(+), 49 deletions(-) create mode 100644 deploy/cpp_infer/docs/windows_vs2019_build.md diff --git a/deploy/cpp_infer/CMakeLists.txt b/deploy/cpp_infer/CMakeLists.txt index 1415e2cb..b8ded08a 100644 --- a/deploy/cpp_infer/CMakeLists.txt +++ b/deploy/cpp_infer/CMakeLists.txt @@ -1,8 +1,16 @@ project(ocr_system CXX C) -option(WITH_MKL "Compile demo with MKL/OpenBlas support, default use MKL." ON) + +option(WITH_MKL "Compile demo with MKL/OpenBlas support, default use MKL." OFF) option(WITH_GPU "Compile demo with GPU/CPU, default use CPU." OFF) option(WITH_STATIC_LIB "Compile demo with static/shared library, default use static." ON) -option(USE_TENSORRT "Compile demo with TensorRT." OFF) + +SET(PADDLE_LIB "" CACHE PATH "Location of libraries") +SET(OPENCV_DIR "" CACHE PATH "Location of libraries") +SET(CUDA_LIB "" CACHE PATH "Location of libraries") +SET(CUDNN_LIB "" CACHE PATH "Location of libraries") +SET(TENSORRT_DIR "" CACHE PATH "Compile demo with TensorRT") + +set(DEMO_NAME "ocr_system") macro(safe_set_static_flag) @@ -15,24 +23,60 @@ macro(safe_set_static_flag) endforeach(flag_var) endmacro() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -fpermissive") -set(CMAKE_STATIC_LIBRARY_PREFIX "") -message("flags" ${CMAKE_CXX_FLAGS}) -set(CMAKE_CXX_FLAGS_RELEASE "-O3") +if (WITH_MKL) + ADD_DEFINITIONS(-DUSE_MKL) +endif() if(NOT DEFINED PADDLE_LIB) message(FATAL_ERROR "please set PADDLE_LIB with -DPADDLE_LIB=/path/paddle/lib") endif() -if(NOT DEFINED DEMO_NAME) - message(FATAL_ERROR "please set DEMO_NAME with -DDEMO_NAME=demo_name") + +if(NOT DEFINED OPENCV_DIR) + message(FATAL_ERROR "please set OPENCV_DIR with -DOPENCV_DIR=/path/opencv") endif() -set(OPENCV_DIR ${OPENCV_DIR}) -find_package(OpenCV REQUIRED PATHS ${OPENCV_DIR}/share/OpenCV NO_DEFAULT_PATH) +if (WIN32) + include_directories("${PADDLE_LIB}/paddle/fluid/inference") + include_directories("${PADDLE_LIB}/paddle/include") + link_directories("${PADDLE_LIB}/paddle/fluid/inference") + find_package(OpenCV REQUIRED PATHS ${OPENCV_DIR}/build/ NO_DEFAULT_PATH) + +else () + find_package(OpenCV REQUIRED PATHS ${OPENCV_DIR}/share/OpenCV NO_DEFAULT_PATH) + include_directories("${PADDLE_LIB}/paddle/include") + link_directories("${PADDLE_LIB}/paddle/lib") +endif () include_directories(${OpenCV_INCLUDE_DIRS}) -include_directories("${PADDLE_LIB}/paddle/include") +if (WIN32) + add_definitions("/DGOOGLE_GLOG_DLL_DECL=") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /bigobj /MTd") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /bigobj /MT") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj /MTd") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /bigobj /MT") + if (WITH_STATIC_LIB) + safe_set_static_flag() + add_definitions(-DSTATIC_LIB) + endif() +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -o3 -std=c++11") + set(CMAKE_STATIC_LIBRARY_PREFIX "") +endif() +message("flags" ${CMAKE_CXX_FLAGS}) + + +if (WITH_GPU) + if (NOT DEFINED CUDA_LIB OR ${CUDA_LIB} STREQUAL "") + message(FATAL_ERROR "please set CUDA_LIB with -DCUDA_LIB=/path/cuda-8.0/lib64") + endif() + if (NOT WIN32) + if (NOT DEFINED CUDNN_LIB) + message(FATAL_ERROR "please set CUDNN_LIB with -DCUDNN_LIB=/path/cudnn_v7.4/cuda/lib64") + endif() + endif(NOT WIN32) +endif() + include_directories("${PADDLE_LIB}/third_party/install/protobuf/include") include_directories("${PADDLE_LIB}/third_party/install/glog/include") include_directories("${PADDLE_LIB}/third_party/install/gflags/include") @@ -43,10 +87,12 @@ include_directories("${PADDLE_LIB}/third_party/eigen3") include_directories("${CMAKE_SOURCE_DIR}/") -if (USE_TENSORRT AND WITH_GPU) - include_directories("${TENSORRT_ROOT}/include") - link_directories("${TENSORRT_ROOT}/lib") -endif() +if (NOT WIN32) + if (WITH_TENSORRT AND WITH_GPU) + include_directories("${TENSORRT_DIR}/include") + link_directories("${TENSORRT_DIR}/lib") + endif() +endif(NOT WIN32) link_directories("${PADDLE_LIB}/third_party/install/zlib/lib") @@ -57,17 +103,24 @@ link_directories("${PADDLE_LIB}/third_party/install/xxhash/lib") link_directories("${PADDLE_LIB}/paddle/lib") -AUX_SOURCE_DIRECTORY(./src SRCS) -add_executable(${DEMO_NAME} ${SRCS}) - if(WITH_MKL) include_directories("${PADDLE_LIB}/third_party/install/mklml/include") - set(MATH_LIB ${PADDLE_LIB}/third_party/install/mklml/lib/libmklml_intel${CMAKE_SHARED_LIBRARY_SUFFIX} - ${PADDLE_LIB}/third_party/install/mklml/lib/libiomp5${CMAKE_SHARED_LIBRARY_SUFFIX}) + if (WIN32) + set(MATH_LIB ${PADDLE_LIB}/third_party/install/mklml/lib/mklml.lib + ${PADDLE_LIB}/third_party/install/mklml/lib/libiomp5md.lib) + else () + set(MATH_LIB ${PADDLE_LIB}/third_party/install/mklml/lib/libmklml_intel${CMAKE_SHARED_LIBRARY_SUFFIX} + ${PADDLE_LIB}/third_party/install/mklml/lib/libiomp5${CMAKE_SHARED_LIBRARY_SUFFIX}) + execute_process(COMMAND cp -r ${PADDLE_LIB}/third_party/install/mklml/lib/libmklml_intel${CMAKE_SHARED_LIBRARY_SUFFIX} /usr/lib) + endif () set(MKLDNN_PATH "${PADDLE_LIB}/third_party/install/mkldnn") if(EXISTS ${MKLDNN_PATH}) include_directories("${MKLDNN_PATH}/include") - set(MKLDNN_LIB ${MKLDNN_PATH}/lib/libmkldnn.so.0) + if (WIN32) + set(MKLDNN_LIB ${MKLDNN_PATH}/lib/mkldnn.lib) + else () + set(MKLDNN_LIB ${MKLDNN_PATH}/lib/libmkldnn.so.0) + endif () endif() else() set(MATH_LIB ${PADDLE_LIB}/third_party/install/openblas/lib/libopenblas${CMAKE_STATIC_LIBRARY_SUFFIX}) @@ -82,24 +135,66 @@ else() ${PADDLE_LIB}/paddle/lib/libpaddle_fluid${CMAKE_SHARED_LIBRARY_SUFFIX}) endif() -set(EXTERNAL_LIB "-lrt -ldl -lpthread -lm") +if (NOT WIN32) + set(DEPS ${DEPS} + ${MATH_LIB} ${MKLDNN_LIB} + glog gflags protobuf z xxhash + ) + if(EXISTS "${PADDLE_LIB}/third_party/install/snappystream/lib") + set(DEPS ${DEPS} snappystream) + endif() + if (EXISTS "${PADDLE_LIB}/third_party/install/snappy/lib") + set(DEPS ${DEPS} snappy) + endif() +else() + set(DEPS ${DEPS} + ${MATH_LIB} ${MKLDNN_LIB} + glog gflags_static libprotobuf xxhash) + set(DEPS ${DEPS} libcmt shlwapi) + if (EXISTS "${PADDLE_LIB}/third_party/install/snappy/lib") + set(DEPS ${DEPS} snappy) + endif() + if(EXISTS "${PADDLE_LIB}/third_party/install/snappystream/lib") + set(DEPS ${DEPS} snappystream) + endif() +endif(NOT WIN32) -set(DEPS ${DEPS} - ${MATH_LIB} ${MKLDNN_LIB} - glog gflags protobuf z xxhash - ${EXTERNAL_LIB} ${OpenCV_LIBS}) if(WITH_GPU) - if (USE_TENSORRT) - set(DEPS ${DEPS} - ${TENSORRT_ROOT}/lib/libnvinfer${CMAKE_SHARED_LIBRARY_SUFFIX}) - set(DEPS ${DEPS} - ${TENSORRT_ROOT}/lib/libnvinfer_plugin${CMAKE_SHARED_LIBRARY_SUFFIX}) + if(NOT WIN32) + if (WITH_TENSORRT) + set(DEPS ${DEPS} ${TENSORRT_DIR}/lib/libnvinfer${CMAKE_SHARED_LIBRARY_SUFFIX}) + set(DEPS ${DEPS} ${TENSORRT_DIR}/lib/libnvinfer_plugin${CMAKE_SHARED_LIBRARY_SUFFIX}) + endif() + set(DEPS ${DEPS} ${CUDA_LIB}/libcudart${CMAKE_SHARED_LIBRARY_SUFFIX}) + set(DEPS ${DEPS} ${CUDNN_LIB}/libcudnn${CMAKE_SHARED_LIBRARY_SUFFIX}) + else() + set(DEPS ${DEPS} ${CUDA_LIB}/cudart${CMAKE_STATIC_LIBRARY_SUFFIX} ) + set(DEPS ${DEPS} ${CUDA_LIB}/cublas${CMAKE_STATIC_LIBRARY_SUFFIX} ) + set(DEPS ${DEPS} ${CUDNN_LIB}/cudnn${CMAKE_STATIC_LIBRARY_SUFFIX}) endif() - set(DEPS ${DEPS} ${CUDA_LIB}/libcudart${CMAKE_SHARED_LIBRARY_SUFFIX}) - set(DEPS ${DEPS} ${CUDA_LIB}/libcudart${CMAKE_SHARED_LIBRARY_SUFFIX} ) - set(DEPS ${DEPS} ${CUDA_LIB}/libcublas${CMAKE_SHARED_LIBRARY_SUFFIX} ) - set(DEPS ${DEPS} ${CUDNN_LIB}/libcudnn${CMAKE_SHARED_LIBRARY_SUFFIX} ) endif() + +if (NOT WIN32) + set(EXTERNAL_LIB "-ldl -lrt -lgomp -lz -lm -lpthread") + set(DEPS ${DEPS} ${EXTERNAL_LIB}) +endif() + +set(DEPS ${DEPS} ${OpenCV_LIBS}) + +AUX_SOURCE_DIRECTORY(./src SRCS) +add_executable(${DEMO_NAME} ${SRCS}) + target_link_libraries(${DEMO_NAME} ${DEPS}) + +if (WIN32 AND WITH_MKL) + add_custom_command(TARGET ${DEMO_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PADDLE_LIB}/third_party/install/mklml/lib/mklml.dll ./mklml.dll + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PADDLE_LIB}/third_party/install/mklml/lib/libiomp5md.dll ./libiomp5md.dll + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PADDLE_LIB}/third_party/install/mkldnn/lib/mkldnn.dll ./mkldnn.dll + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PADDLE_LIB}/third_party/install/mklml/lib/mklml.dll ./release/mklml.dll + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PADDLE_LIB}/third_party/install/mklml/lib/libiomp5md.dll ./release/libiomp5md.dll + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PADDLE_LIB}/third_party/install/mkldnn/lib/mkldnn.dll ./release/mkldnn.dll + ) +endif() \ No newline at end of file diff --git a/deploy/cpp_infer/docs/windows_vs2019_build.md b/deploy/cpp_infer/docs/windows_vs2019_build.md new file mode 100644 index 00000000..21fbf4e0 --- /dev/null +++ b/deploy/cpp_infer/docs/windows_vs2019_build.md @@ -0,0 +1,95 @@ +# Visual Studio 2019 Community CMake 编译指南 + +PaddleOCR在Windows 平台下基于`Visual Studio 2019 Community` 进行了测试。微软从`Visual Studio 2017`开始即支持直接管理`CMake`跨平台编译项目,但是直到`2019`才提供了稳定和完全的支持,所以如果你想使用CMake管理项目编译构建,我们推荐你使用`Visual Studio 2019`环境下构建。 + + +## 前置条件 +* Visual Studio 2019 +* CUDA 9.0 / CUDA 10.0,cudnn 7+ (仅在使用GPU版本的预测库时需要) +* CMake 3.0+ + +请确保系统已经安装好上述基本软件,我们使用的是`VS2019`的社区版。 + +**下面所有示例以工作目录为 `D:\projects`演示**。 + +### Step1: 下载PaddlePaddle C++ 预测库 fluid_inference + +PaddlePaddle C++ 预测库针对不同的`CPU`和`CUDA`版本提供了不同的预编译版本,请根据实际情况下载: [C++预测库下载列表](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/advanced_guide/inference_deployment/inference/windows_cpp_inference.html) + +解压后`D:\projects\fluid_inference`目录包含内容为: +``` +fluid_inference +├── paddle # paddle核心库和头文件 +| +├── third_party # 第三方依赖库和头文件 +| +└── version.txt # 版本和编译信息 +``` + +### Step2: 安装配置OpenCV + +1. 在OpenCV官网下载适用于Windows平台的3.4.6版本, [下载地址](https://sourceforge.net/projects/opencvlibrary/files/3.4.6/opencv-3.4.6-vc14_vc15.exe/download) +2. 运行下载的可执行文件,将OpenCV解压至指定目录,如`D:\projects\opencv` +3. 配置环境变量,如下流程所示 + - 我的电脑->属性->高级系统设置->环境变量 + - 在系统变量中找到Path(如没有,自行创建),并双击编辑 + - 新建,将opencv路径填入并保存,如`D:\projects\opencv\build\x64\vc14\bin` + +### Step3: 使用Visual Studio 2019直接编译CMake + +1. 打开Visual Studio 2019 Community,点击`继续但无需代码` +![step2](https://paddleseg.bj.bcebos.com/inference/vs2019_step1.png) +2. 点击: `文件`->`打开`->`CMake` +![step2.1](https://paddleseg.bj.bcebos.com/inference/vs2019_step2.png) + +选择项目代码所在路径,并打开`CMakeList.txt`: + +![step2.2](https://paddleseg.bj.bcebos.com/inference/vs2019_step3.png) + +3. 点击:`项目`->`cpp_inference_demo的CMake设置` + +![step3](https://paddleseg.bj.bcebos.com/inference/vs2019_step4.png) + +4. 点击`浏览`,分别设置编译选项指定`CUDA`、`CUDNN_LIB`、`OpenCV`、`Paddle预测库`的路径 + +三个编译参数的含义说明如下(带`*`表示仅在使用**GPU版本**预测库时指定, 其中CUDA库版本尽量对齐,**使用9.0、10.0版本,不使用9.2、10.1等版本CUDA库**): + +| 参数名 | 含义 | +| ---- | ---- | +| *CUDA_LIB | CUDA的库路径 | +| *CUDNN_LIB | CUDNN的库路径 | +| OPENCV_DIR | OpenCV的安装路径 | +| PADDLE_LIB | Paddle预测库的路径 | + +**注意:** + 1. 使用`CPU`版预测库,请把`WITH_GPU`的勾去掉 + 2. 如果使用的是`openblas`版本,请把`WITH_MKL`勾去掉 + +![step4](https://paddleseg.bj.bcebos.com/inference/vs2019_step5.png) + +**设置完成后**, 点击上图中`保存并生成CMake缓存以加载变量`。 + +5. 点击`生成`->`全部生成` + +![step6](https://paddleseg.bj.bcebos.com/inference/vs2019_step6.png) + + +### Step4: 预测及可视化 + +上述`Visual Studio 2019`编译产出的可执行文件在`out\build\x64-Release`目录下,打开`cmd`,并切换到该目录: + +``` +cd D:\projects\PaddleOCR\deploy\cpp_infer\out\build\x64-Release +``` +可执行文件`ocr_system.exe`即为样例的预测程序,其主要使用方法如下 + +```shell +#预测图片 `D:\projects\PaddleOCR\doc\imgs\10.jpg` +.\ocr_system.exe D:\projects\PaddleOCR\deploy\cpp_infer\tools\config.txt D:\projects\PaddleOCR\doc\imgs\10.jpg +``` + +第一个参数为配置文件路径,第二个参数为需要预测的图片路径。 + + +### 注意 +* 在Windows下的终端中执行文件exe时,可能会发生乱码的现象,此时需要在终端中输入`CHCP 65001`,将终端的编码方式由GBK编码(默认)改为UTF-8编码,更加具体的解释可以参考这篇博客:[https://blog.csdn.net/qq_35038153/article/details/78430359](https://blog.csdn.net/qq_35038153/article/details/78430359)。 diff --git a/deploy/cpp_infer/readme.md b/deploy/cpp_infer/readme.md index 03db8c50..0b244109 100644 --- a/deploy/cpp_infer/readme.md +++ b/deploy/cpp_infer/readme.md @@ -7,6 +7,9 @@ ### 运行准备 - Linux环境,推荐使用docker。 +- Windows环境,目前支持基于`Visual Studio 2019 Community`进行编译。 + +* 该文档主要介绍基于Linux环境的PaddleOCR C++预测流程,如果需要在Windows下基于预测库进行C++预测,具体编译方法请参考[Windows下编译教程](./docs/windows_vs2019_build.md) ### 1.1 编译opencv库 diff --git a/deploy/cpp_infer/src/config.cpp b/deploy/cpp_infer/src/config.cpp index 228c874d..52dfa209 100644 --- a/deploy/cpp_infer/src/config.cpp +++ b/deploy/cpp_infer/src/config.cpp @@ -44,7 +44,7 @@ Config::LoadConfig(const std::string &config_path) { std::map dict; for (int i = 0; i < config.size(); i++) { // pass for empty line or comment - if (config[i].size() <= 1 or config[i][0] == '#') { + if (config[i].size() <= 1 || config[i][0] == '#') { continue; } std::vector res = split(config[i], " "); diff --git a/deploy/cpp_infer/src/utility.cpp b/deploy/cpp_infer/src/utility.cpp index ffb74c2e..cbff2a71 100644 --- a/deploy/cpp_infer/src/utility.cpp +++ b/deploy/cpp_infer/src/utility.cpp @@ -39,22 +39,28 @@ std::vector Utility::ReadDict(const std::string &path) { void Utility::VisualizeBboxes( const cv::Mat &srcimg, const std::vector>> &boxes) { - cv::Point rook_points[boxes.size()][4]; - for (int n = 0; n < boxes.size(); n++) { - for (int m = 0; m < boxes[0].size(); m++) { - rook_points[n][m] = cv::Point(int(boxes[n][m][0]), int(boxes[n][m][1])); - } - } + // cv::Point rook_points[boxes.size()][4]; + // for (int n = 0; n < boxes.size(); n++) { + // for (int m = 0; m < boxes[0].size(); m++) { + // rook_points[n][m] = cv::Point(int(boxes[n][m][0]), + // int(boxes[n][m][1])); + // } + // } cv::Mat img_vis; srcimg.copyTo(img_vis); for (int n = 0; n < boxes.size(); n++) { - const cv::Point *ppt[1] = {rook_points[n]}; + cv::Point rook_points[4]; + for (int m = 0; m < boxes[n].size(); m++) { + rook_points[m] = cv::Point(int(boxes[n][m][0]), int(boxes[n][m][1])); + } + + const cv::Point *ppt[1] = {rook_points}; int npt[] = {4}; cv::polylines(img_vis, ppt, npt, 1, 1, CV_RGB(0, 255, 0), 2, 8, 0); } cv::imwrite("./ocr_vis.png", img_vis); - std::cout << "The detection visualized image saved in ./ocr_vis.png.pn" + std::cout << "The detection visualized image saved in ./ocr_vis.png" << std::endl; } diff --git a/deploy/cpp_infer/tools/build.sh b/deploy/cpp_infer/tools/build.sh index d8344a23..60653948 100755 --- a/deploy/cpp_infer/tools/build.sh +++ b/deploy/cpp_infer/tools/build.sh @@ -1,8 +1,7 @@ - OPENCV_DIR=your_opencv_dir LIB_DIR=your_paddle_inference_dir CUDA_LIB_DIR=your_cuda_lib_dir -CUDNN_LIB_DIR=/your_cudnn_lib_dir +CUDNN_LIB_DIR=your_cudnn_lib_dir BUILD_DIR=build rm -rf ${BUILD_DIR} @@ -11,7 +10,6 @@ cd ${BUILD_DIR} cmake .. \ -DPADDLE_LIB=${LIB_DIR} \ -DWITH_MKL=ON \ - -DDEMO_NAME=ocr_system \ -DWITH_GPU=OFF \ -DWITH_STATIC_LIB=OFF \ -DUSE_TENSORRT=OFF \ diff --git a/deploy/cpp_infer/tools/config.txt b/deploy/cpp_infer/tools/config.txt index fe7f27a0..a049fc7d 100644 --- a/deploy/cpp_infer/tools/config.txt +++ b/deploy/cpp_infer/tools/config.txt @@ -15,8 +15,7 @@ det_model_dir ./inference/det_db # rec config rec_model_dir ./inference/rec_crnn char_list_file ../../ppocr/utils/ppocr_keys_v1.txt -img_path ../../doc/imgs/11.jpg # show the detection results -visualize 0 +visualize 1 From 59ca349fe458f84be4d1ef73fd7ea92ee9b5943e Mon Sep 17 00:00:00 2001 From: littletomatodonkey Date: Mon, 20 Jul 2020 17:29:40 +0000 Subject: [PATCH 06/26] fix format --- deploy/cpp_infer/CMakeLists.txt | 3 ++- deploy/cpp_infer/src/utility.cpp | 7 ------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/deploy/cpp_infer/CMakeLists.txt b/deploy/cpp_infer/CMakeLists.txt index b8ded08a..466c2be8 100644 --- a/deploy/cpp_infer/CMakeLists.txt +++ b/deploy/cpp_infer/CMakeLists.txt @@ -1,8 +1,9 @@ project(ocr_system CXX C) -option(WITH_MKL "Compile demo with MKL/OpenBlas support, default use MKL." OFF) +option(WITH_MKL "Compile demo with MKL/OpenBlas support, default use MKL." ON) option(WITH_GPU "Compile demo with GPU/CPU, default use CPU." OFF) option(WITH_STATIC_LIB "Compile demo with static/shared library, default use static." ON) +option(WITH_TENSORRT "Compile demo with TensorRT." OFF) SET(PADDLE_LIB "" CACHE PATH "Location of libraries") SET(OPENCV_DIR "" CACHE PATH "Location of libraries") diff --git a/deploy/cpp_infer/src/utility.cpp b/deploy/cpp_infer/src/utility.cpp index cbff2a71..c1c9d938 100644 --- a/deploy/cpp_infer/src/utility.cpp +++ b/deploy/cpp_infer/src/utility.cpp @@ -39,13 +39,6 @@ std::vector Utility::ReadDict(const std::string &path) { void Utility::VisualizeBboxes( const cv::Mat &srcimg, const std::vector>> &boxes) { - // cv::Point rook_points[boxes.size()][4]; - // for (int n = 0; n < boxes.size(); n++) { - // for (int m = 0; m < boxes[0].size(); m++) { - // rook_points[n][m] = cv::Point(int(boxes[n][m][0]), - // int(boxes[n][m][1])); - // } - // } cv::Mat img_vis; srcimg.copyTo(img_vis); for (int n = 0; n < boxes.size(); n++) { From 7576c8a66f5dab737dcbc7234acabb45a109978e Mon Sep 17 00:00:00 2001 From: dyning Date: Tue, 21 Jul 2020 15:47:14 +0800 Subject: [PATCH 07/26] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 60ea75b7..3d665771 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ English | [简体中文](README_cn.md) +## **Live stream**: July 21, 2020 at 8 pm BiliBili station + +**Live address:https://live.bilibili.com/h5/21689802** + ## Introduction PaddleOCR aims to create rich, leading, and practical OCR tools that help users train better models and apply them into practice. -**Live stream on coming day**: July 21, 2020 at 8 pm BiliBili station live stream - -Live address:https://live.bilibili.com/h5/21689802 - **Recent updates** - 2020.7.15, Add mobile App demo , support both iOS and Android ( based on easyedge and Paddle Lite) From 54829530724151894d4d08ae29c0051214b539c4 Mon Sep 17 00:00:00 2001 From: dyning Date: Tue, 21 Jul 2020 15:48:49 +0800 Subject: [PATCH 08/26] Update README_cn.md --- README_cn.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README_cn.md b/README_cn.md index 7b3c3fec..a3ffa13d 100644 --- a/README_cn.md +++ b/README_cn.md @@ -1,12 +1,12 @@ [English](README.md) | 简体中文 +## **直播:2020年7月21日晚8点B站直播,PaddleOCR开源大礼包全面解读** + +**直播地址:https://live.bilibili.com/21689802** + ## 简介 PaddleOCR旨在打造一套丰富、领先、且实用的OCR工具库,助力使用者训练出更好的模型,并应用落地。 -**直播预告:2020年7月21日晚8点B站直播,PaddleOCR开源大礼包全面解读** - -直播地址:https://live.bilibili.com/21689802 - **近期更新** - 2020.7.15 添加基于EasyEdge和Paddle-Lite的移动端DEMO,支持iOS和Android系统 - 2020.7.15 完善预测部署,添加基于C++预测引擎推理、服务化部署和端侧部署方案,以及超轻量级中文OCR模型预测耗时Benchmark From 395d83d36c9c7251fc53f3bb65f4ce2ce7148296 Mon Sep 17 00:00:00 2001 From: dyning Date: Tue, 21 Jul 2020 15:54:30 +0800 Subject: [PATCH 09/26] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d665771..ed98d688 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ English | [简体中文](README_cn.md) -## **Live stream**: July 21, 2020 at 8 pm BiliBili station +## **Live stream**: July 21, 2020 at 8 pm BiliBili station,PaddleOCR Introduction **Live address:https://live.bilibili.com/h5/21689802** From 422130966895d31ba7dd7afd45c3d7a982b31794 Mon Sep 17 00:00:00 2001 From: wangjiawei04 Date: Tue, 21 Jul 2020 19:19:36 +0800 Subject: [PATCH 10/26] fix readme --- deploy/pdserving/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/pdserving/readme.md b/deploy/pdserving/readme.md index bab44249..17378b10 100644 --- a/deploy/pdserving/readme.md +++ b/deploy/pdserving/readme.md @@ -67,7 +67,7 @@ python ocr_web_client.py ## 自定义修改服务逻辑 -在`ocr_web_server.py`或是`ocr_debugger_server.py`当中的`preprocess`函数里面做了检测服务和识别服务的前处理,·`postprocess`函数里面做了识别的后处理服务,可以在相应的函数中做修改。调用了`paddle_serving_app`库提供的常见CV模型的前处理/后处理库。 +在`ocr_web_server.py`或是`ocr_local_server.py`当中的`preprocess`函数里面做了检测服务和识别服务的前处理,`postprocess`函数里面做了识别的后处理服务,可以在相应的函数中做修改。调用了`paddle_serving_app`库提供的常见CV模型的前处理/后处理库。 如果想要单独启动Paddle Serving的检测服务和识别服务,参见下列表格, 执行对应的脚本即可。 From ba69b2d480ff4a5ce16b34630f4c33fda6f9c773 Mon Sep 17 00:00:00 2001 From: wangjiawei04 Date: Tue, 21 Jul 2020 19:22:25 +0800 Subject: [PATCH 11/26] fix readme --- deploy/pdserving/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/pdserving/readme.md b/deploy/pdserving/readme.md index 17378b10..b77ffea9 100644 --- a/deploy/pdserving/readme.md +++ b/deploy/pdserving/readme.md @@ -8,8 +8,8 @@ 我们先安装Paddle Serving相关组件 我们推荐用户使用GPU来做Paddle Serving的OCR服务部署 -**CUDA版本:9.0以上** -**CUDNN版本:7.0以上** +**CUDA版本:9.0** +**CUDNN版本:7.0** **操作系统版本:CentOS 6以上** ``` From 205dea7ecf5d2b85e6df4f3690520889e24fc04d Mon Sep 17 00:00:00 2001 From: wangjiawei04 Date: Tue, 21 Jul 2020 20:00:36 +0800 Subject: [PATCH 12/26] fix readme(mark beta) --- deploy/pdserving/readme.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/deploy/pdserving/readme.md b/deploy/pdserving/readme.md index b77ffea9..e711369f 100644 --- a/deploy/pdserving/readme.md +++ b/deploy/pdserving/readme.md @@ -1,4 +1,4 @@ -# Paddle Serving 服务部署 +# Paddle Serving 服务部署(Beta) 本教程将介绍基于[Paddle Serving](https://github.com/PaddlePaddle/Serving)部署PaddleOCR在线预测服务的详细步骤。 @@ -13,7 +13,11 @@ **操作系统版本:CentOS 6以上** ``` -python -m pip install paddle_serving_server_gpu paddle_serving_client paddle_serving_app +#以下提供beta版本的paddle serving whl包,欢迎试用,正式版会在7月底正式上线 +wget --no-check-certificate https://paddle-serving.bj.bcebos.com/others/paddle_serving_server_gpu-0.3.2-py2-none-any.whl +wget --no-check-certificate https://paddle-serving.bj.bcebos.com/others/paddle_serving_app-0.1.2-py2-none-any.whl +python -m pip install paddle_serving_app-0.1.2-py2-none-any.whl paddle_serving_server_gpu-0.3.2-py2-none-any.whl +python -m pip install paddle_serving_client ``` ### 2. 模型转换 From 64512c7c57795690a1c6ec5d11608697243bfc77 Mon Sep 17 00:00:00 2001 From: wangjiawei04 Date: Tue, 21 Jul 2020 20:24:26 +0800 Subject: [PATCH 13/26] fix readme(mark beta) --- deploy/pdserving/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/pdserving/readme.md b/deploy/pdserving/readme.md index e711369f..4ec42d79 100644 --- a/deploy/pdserving/readme.md +++ b/deploy/pdserving/readme.md @@ -16,8 +16,8 @@ #以下提供beta版本的paddle serving whl包,欢迎试用,正式版会在7月底正式上线 wget --no-check-certificate https://paddle-serving.bj.bcebos.com/others/paddle_serving_server_gpu-0.3.2-py2-none-any.whl wget --no-check-certificate https://paddle-serving.bj.bcebos.com/others/paddle_serving_app-0.1.2-py2-none-any.whl -python -m pip install paddle_serving_app-0.1.2-py2-none-any.whl paddle_serving_server_gpu-0.3.2-py2-none-any.whl -python -m pip install paddle_serving_client +wget --no-check-certificate https://paddle-serving.bj.bcebos.com/others/paddle_serving_client-0.3.2-cp27-none-any.whl +python -m pip install paddle_serving_app-0.1.2-py2-none-any.whl paddle_serving_server_gpu-0.3.2-py2-none-any.whl paddle_serving_client-0.3.2-cp27-none-any.whl ``` ### 2. 模型转换 From 9d33e36df550762b204d5fbfd7977a25e31b2c44 Mon Sep 17 00:00:00 2001 From: MissPenguin Date: Wed, 22 Jul 2020 10:37:21 +0800 Subject: [PATCH 14/26] Update serving.md --- doc/doc_ch/serving.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/doc_ch/serving.md b/doc/doc_ch/serving.md index 0b5eff3f..1cc57d53 100644 --- a/doc/doc_ch/serving.md +++ b/doc/doc_ch/serving.md @@ -69,7 +69,7 @@ $ hub serving start --modules [Module1==Version1, Module2==Version2, ...] \ #### 方式2. 配置文件启动(支持CPU、GPU) **启动命令:** -```hub serving start --config/-c config.json``` +```hub serving start -c config.json``` 其中,`config.json`格式如下: ```python From 4cbcee2ddba757be83df3fa3e63609f628e616ff Mon Sep 17 00:00:00 2001 From: authorfu Date: Wed, 22 Jul 2020 16:08:18 +0800 Subject: [PATCH 15/26] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=8B=8D=E7=85=A7?= =?UTF-8?q?=E4=B8=8D=E6=B8=85=E6=99=B0=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/src/main/AndroidManifest.xml | 9 +++ .../paddle/lite/demo/ocr/MainActivity.java | 72 +++++++++++++++++-- .../lite/demo/ocr/OCRPredictorNative.java | 4 +- .../baidu/paddle/lite/demo/ocr/Predictor.java | 12 ++-- .../com/baidu/paddle/lite/demo/ocr/Utils.java | 46 ++++++++++++ .../app/src/main/res/xml/file_paths.xml | 4 ++ 6 files changed, 131 insertions(+), 16 deletions(-) create mode 100644 deploy/android_demo/app/src/main/res/xml/file_paths.xml diff --git a/deploy/android_demo/app/src/main/AndroidManifest.xml b/deploy/android_demo/app/src/main/AndroidManifest.xml index ff1900d6..b7c1d8b5 100644 --- a/deploy/android_demo/app/src/main/AndroidManifest.xml +++ b/deploy/android_demo/app/src/main/AndroidManifest.xml @@ -25,6 +25,15 @@ android:name="com.baidu.paddle.lite.demo.ocr.SettingsActivity" android:label="Settings"> + + + \ No newline at end of file diff --git a/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/MainActivity.java b/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/MainActivity.java index b72d72df..716e7bdd 100644 --- a/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/MainActivity.java +++ b/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/MainActivity.java @@ -3,14 +3,17 @@ package com.baidu.paddle.lite.demo.ocr; import android.Manifest; import android.app.ProgressDialog; import android.content.ContentResolver; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.media.ExifInterface; import android.net.Uri; import android.os.Bundle; +import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; @@ -19,6 +22,7 @@ import android.provider.MediaStore; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; +import android.support.v4.content.FileProvider; import android.support.v7.app.AppCompatActivity; import android.text.method.ScrollingMovementMethod; import android.util.Log; @@ -32,6 +36,8 @@ import android.widget.Toast; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.Date; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); @@ -69,6 +75,7 @@ public class MainActivity extends AppCompatActivity { protected float[] inputMean = new float[]{}; protected float[] inputStd = new float[]{}; protected float scoreThreshold = 0.1f; + private String currentPhotoPath; protected Predictor predictor = new Predictor(); @@ -368,18 +375,56 @@ public class MainActivity extends AppCompatActivity { } private void takePhoto() { - Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - if (takePhotoIntent.resolveActivity(getPackageManager()) != null) { - startActivityForResult(takePhotoIntent, TAKE_PHOTO_REQUEST_CODE); + Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + // Ensure that there's a camera activity to handle the intent + if (takePictureIntent.resolveActivity(getPackageManager()) != null) { + // Create the File where the photo should go + File photoFile = null; + try { + photoFile = createImageFile(); + } catch (IOException ex) { + Log.e("MainActitity", ex.getMessage(), ex); + Toast.makeText(MainActivity.this, + "Create Camera temp file failed: " + ex.getMessage(), Toast.LENGTH_SHORT).show(); + } + // Continue only if the File was successfully created + if (photoFile != null) { + Log.i(TAG, "FILEPATH " + getExternalFilesDir("Pictures").getAbsolutePath()); + Uri photoURI = FileProvider.getUriForFile(this, + "com.baidu.paddle.lite.demo.ocr.fileprovider", + photoFile); + currentPhotoPath = photoFile.getAbsolutePath(); + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); + startActivityForResult(takePictureIntent, TAKE_PHOTO_REQUEST_CODE); + Log.i(TAG, "startActivityForResult finished"); + } } + + } + + private File createImageFile() throws IOException { + // Create an image file name + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); + String imageFileName = "JPEG_" + timeStamp + "_"; + File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); + File image = File.createTempFile( + imageFileName, /* prefix */ + ".bmp", /* suffix */ + storageDir /* directory */ + ); + + return image; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (resultCode == RESULT_OK && data != null) { + if (resultCode == RESULT_OK) { switch (requestCode) { case OPEN_GALLERY_REQUEST_CODE: + if (data == null) { + break; + } try { ContentResolver resolver = getContentResolver(); Uri uri = data.getData(); @@ -393,9 +438,22 @@ public class MainActivity extends AppCompatActivity { } break; case TAKE_PHOTO_REQUEST_CODE: - Bundle extras = data.getExtras(); - Bitmap image = (Bitmap) extras.get("data"); - onImageChanged(image); + if (currentPhotoPath != null) { + ExifInterface exif = null; + try { + exif = new ExifInterface(currentPhotoPath); + } catch (IOException e) { + e.printStackTrace(); + } + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, + ExifInterface.ORIENTATION_UNDEFINED); + Log.i(TAG, "rotation " + orientation); + Bitmap image = BitmapFactory.decodeFile(currentPhotoPath); + image = Utils.rotateBitmap(image, orientation); + onImageChanged(image); + } else { + Log.e(TAG, "currentPhotoPath is null"); + } break; default: break; diff --git a/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/OCRPredictorNative.java b/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/OCRPredictorNative.java index 103d5d37..2e78a3ec 100644 --- a/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/OCRPredictorNative.java +++ b/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/OCRPredictorNative.java @@ -35,8 +35,8 @@ public class OCRPredictorNative { } - public void release(){ - if (nativePointer != 0){ + public void release() { + if (nativePointer != 0) { nativePointer = 0; destory(nativePointer); } diff --git a/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/Predictor.java b/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/Predictor.java index d491481e..7543acee 100644 --- a/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/Predictor.java +++ b/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/Predictor.java @@ -127,12 +127,12 @@ public class Predictor { } public void releaseModel() { - if (paddlePredictor != null){ + if (paddlePredictor != null) { paddlePredictor.release(); paddlePredictor = null; } isLoaded = false; - cpuThreadNum = 4; + cpuThreadNum = 1; cpuPowerMode = "LITE_POWER_HIGH"; modelPath = ""; modelName = ""; @@ -287,9 +287,7 @@ public class Predictor { if (image == null) { return; } - // Scale image to the size of input tensor - Bitmap rgbaImage = image.copy(Bitmap.Config.ARGB_8888, true); - this.inputImage = rgbaImage; + this.inputImage = image.copy(Bitmap.Config.ARGB_8888, true); } private ArrayList postprocess(ArrayList results) { @@ -310,7 +308,7 @@ public class Predictor { private void drawResults(ArrayList results) { StringBuffer outputResultSb = new StringBuffer(""); - for (int i=0;i + + + \ No newline at end of file From 070abbc37142242c20a961f7f5a151e8fc26895c Mon Sep 17 00:00:00 2001 From: dyning Date: Thu, 23 Jul 2020 10:03:44 +0800 Subject: [PATCH 16/26] Update README_cn.md --- README_cn.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README_cn.md b/README_cn.md index a3ffa13d..290622fe 100644 --- a/README_cn.md +++ b/README_cn.md @@ -1,13 +1,10 @@ [English](README.md) | 简体中文 -## **直播:2020年7月21日晚8点B站直播,PaddleOCR开源大礼包全面解读** - -**直播地址:https://live.bilibili.com/21689802** - ## 简介 PaddleOCR旨在打造一套丰富、领先、且实用的OCR工具库,助力使用者训练出更好的模型,并应用落地。 **近期更新** +- 2020.7.23 2020年7月21日B站直播课回放和PPT,PaddleOCR开源大礼包全面解读,[获取地址](https://aistudio.baidu.com/aistudio/course/introduce/1519) - 2020.7.15 添加基于EasyEdge和Paddle-Lite的移动端DEMO,支持iOS和Android系统 - 2020.7.15 完善预测部署,添加基于C++预测引擎推理、服务化部署和端侧部署方案,以及超轻量级中文OCR模型预测耗时Benchmark - 2020.7.15 整理OCR相关数据集、常用数据标注以及合成工具 From bb8194f9e621808941172e79862be7b82abc61a5 Mon Sep 17 00:00:00 2001 From: dyning Date: Thu, 23 Jul 2020 10:04:10 +0800 Subject: [PATCH 17/26] Update README_cn.md --- README_cn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_cn.md b/README_cn.md index 290622fe..08cb0cc4 100644 --- a/README_cn.md +++ b/README_cn.md @@ -4,7 +4,7 @@ PaddleOCR旨在打造一套丰富、领先、且实用的OCR工具库,助力使用者训练出更好的模型,并应用落地。 **近期更新** -- 2020.7.23 2020年7月21日B站直播课回放和PPT,PaddleOCR开源大礼包全面解读,[获取地址](https://aistudio.baidu.com/aistudio/course/introduce/1519) +- 2020.7.23 7月21日B站直播课回放和PPT,PaddleOCR开源大礼包全面解读,[获取地址](https://aistudio.baidu.com/aistudio/course/introduce/1519) - 2020.7.15 添加基于EasyEdge和Paddle-Lite的移动端DEMO,支持iOS和Android系统 - 2020.7.15 完善预测部署,添加基于C++预测引擎推理、服务化部署和端侧部署方案,以及超轻量级中文OCR模型预测耗时Benchmark - 2020.7.15 整理OCR相关数据集、常用数据标注以及合成工具 From ebf4d25650790fa1eead8e4010a1b214db3d7c96 Mon Sep 17 00:00:00 2001 From: dyning Date: Thu, 23 Jul 2020 10:04:42 +0800 Subject: [PATCH 18/26] Update update.md --- doc/doc_ch/update.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/doc_ch/update.md b/doc/doc_ch/update.md index 59514aad..b00dbebd 100644 --- a/doc/doc_ch/update.md +++ b/doc/doc_ch/update.md @@ -1,4 +1,5 @@ # 更新 +- 2020.7.23 7月21日B站直播课回放和PPT,PaddleOCR开源大礼包全面解读,[获取地址](https://aistudio.baidu.com/aistudio/course/introduce/1519) - 2020.7.15 添加基于EasyEdge和Paddle-Lite的移动端DEMO,支持iOS和Android系统 - 2020.7.15 完善预测部署,添加基于C++预测引擎推理、服务化部署和端侧部署方案,以及超轻量级中文OCR模型预测耗时Benchmark - 2020.7.15 整理OCR相关数据集、常用数据标注以及合成工具 From 391b3ae539d3b4eadf530054229869e3e2f11f5c Mon Sep 17 00:00:00 2001 From: dyning Date: Thu, 23 Jul 2020 10:05:16 +0800 Subject: [PATCH 19/26] Update update.md --- doc/doc_ch/update.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/doc_ch/update.md b/doc/doc_ch/update.md index b00dbebd..e22d05b4 100644 --- a/doc/doc_ch/update.md +++ b/doc/doc_ch/update.md @@ -1,5 +1,5 @@ # 更新 -- 2020.7.23 7月21日B站直播课回放和PPT,PaddleOCR开源大礼包全面解读,[获取地址](https://aistudio.baidu.com/aistudio/course/introduce/1519) +- 2020.7.23 发布7月21日B站直播课回放和PPT,PaddleOCR开源大礼包全面解读,[获取地址](https://aistudio.baidu.com/aistudio/course/introduce/1519) - 2020.7.15 添加基于EasyEdge和Paddle-Lite的移动端DEMO,支持iOS和Android系统 - 2020.7.15 完善预测部署,添加基于C++预测引擎推理、服务化部署和端侧部署方案,以及超轻量级中文OCR模型预测耗时Benchmark - 2020.7.15 整理OCR相关数据集、常用数据标注以及合成工具 From 0f47c5ce369fc061967f9673854cb41dfe22810e Mon Sep 17 00:00:00 2001 From: dyning Date: Thu, 23 Jul 2020 10:05:36 +0800 Subject: [PATCH 20/26] Update README_cn.md --- README_cn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_cn.md b/README_cn.md index 08cb0cc4..47bddd5d 100644 --- a/README_cn.md +++ b/README_cn.md @@ -4,7 +4,7 @@ PaddleOCR旨在打造一套丰富、领先、且实用的OCR工具库,助力使用者训练出更好的模型,并应用落地。 **近期更新** -- 2020.7.23 7月21日B站直播课回放和PPT,PaddleOCR开源大礼包全面解读,[获取地址](https://aistudio.baidu.com/aistudio/course/introduce/1519) +- 2020.7.23 发布7月21日B站直播课回放和PPT,PaddleOCR开源大礼包全面解读,[获取地址](https://aistudio.baidu.com/aistudio/course/introduce/1519) - 2020.7.15 添加基于EasyEdge和Paddle-Lite的移动端DEMO,支持iOS和Android系统 - 2020.7.15 完善预测部署,添加基于C++预测引擎推理、服务化部署和端侧部署方案,以及超轻量级中文OCR模型预测耗时Benchmark - 2020.7.15 整理OCR相关数据集、常用数据标注以及合成工具 From 3ace934646d67c32b21d70a2204b2d2d537271b8 Mon Sep 17 00:00:00 2001 From: dyning Date: Thu, 23 Jul 2020 10:10:38 +0800 Subject: [PATCH 21/26] Update README.md --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index ed98d688..3e8bae3f 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,10 @@ English | [简体中文](README_cn.md) -## **Live stream**: July 21, 2020 at 8 pm BiliBili station,PaddleOCR Introduction - -**Live address:https://live.bilibili.com/h5/21689802** - ## Introduction PaddleOCR aims to create rich, leading, and practical OCR tools that help users train better models and apply them into practice. **Recent updates** - +- 2020.7.21, Release the playback and PPT of live class on BiliBili station, PaddleOCR Introduction, [address](https://aistudio.baidu.com/aistudio/course/introduce/1519) - 2020.7.15, Add mobile App demo , support both iOS and Android ( based on easyedge and Paddle Lite) - 2020.7.15, Improve the deployment ability, add the C + + inference , serving deployment. In addtion, the benchmarks of the ultra-lightweight OCR model are provided. - 2020.7.15, Add several related datasets, data annotation and synthesis tools. From 279a7845e0c705905eea6a50130132bc124db6a5 Mon Sep 17 00:00:00 2001 From: dyning Date: Thu, 23 Jul 2020 10:11:45 +0800 Subject: [PATCH 22/26] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e8bae3f..95326fa0 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ English | [简体中文](README_cn.md) PaddleOCR aims to create rich, leading, and practical OCR tools that help users train better models and apply them into practice. **Recent updates** -- 2020.7.21, Release the playback and PPT of live class on BiliBili station, PaddleOCR Introduction, [address](https://aistudio.baidu.com/aistudio/course/introduce/1519) +- 2020.7.23, Release the playback and PPT of live class on BiliBili station, PaddleOCR Introduction, [address](https://aistudio.baidu.com/aistudio/course/introduce/1519) - 2020.7.15, Add mobile App demo , support both iOS and Android ( based on easyedge and Paddle Lite) - 2020.7.15, Improve the deployment ability, add the C + + inference , serving deployment. In addtion, the benchmarks of the ultra-lightweight OCR model are provided. - 2020.7.15, Add several related datasets, data annotation and synthesis tools. From 25ba6785b3665be1ce2476b899ec1633b8efeab3 Mon Sep 17 00:00:00 2001 From: dyning Date: Thu, 23 Jul 2020 10:11:56 +0800 Subject: [PATCH 23/26] Update update_en.md --- doc/doc_en/update_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/doc_en/update_en.md b/doc/doc_en/update_en.md index 6cd347a8..ef02d9db 100644 --- a/doc/doc_en/update_en.md +++ b/doc/doc_en/update_en.md @@ -1,5 +1,5 @@ # RECENT UPDATES - +- 2020.7.23, Release the playback and PPT of live class on BiliBili station, PaddleOCR Introduction, [address](https://aistudio.baidu.com/aistudio/course/introduce/1519) - 2020.7.15, Add mobile App demo , support both iOS and Android ( based on easyedge and Paddle Lite) - 2020.7.15, Improve the deployment ability, add the C + + inference , serving deployment. In addtion, the benchmarks of the ultra-lightweight Chinese OCR model are provided. - 2020.7.15, Add several related datasets, data annotation and synthesis tools. From a52ee64d459f90d1f578defbb7579f10cfe145fe Mon Sep 17 00:00:00 2001 From: LDOUBLEV Date: Thu, 23 Jul 2020 10:37:39 +0800 Subject: [PATCH 24/26] fix lite readme --- deploy/lite/readme.md | 4 ++-- deploy/lite/readme_en.md | 2 +- ppocr/modeling/backbones/rec_mobilenet_v3.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/lite/readme.md b/deploy/lite/readme.md index 378a3eec..219cc83f 100644 --- a/deploy/lite/readme.md +++ b/deploy/lite/readme.md @@ -18,7 +18,7 @@ Paddle Lite是飞桨轻量化推理引擎,为手机、IOT端提供高效推理 1. [Docker](https://paddle-lite.readthedocs.io/zh/latest/user_guides/source_compile.html#docker) 2. [Linux](https://paddle-lite.readthedocs.io/zh/latest/user_guides/source_compile.html#android) 3. [MAC OS](https://paddle-lite.readthedocs.io/zh/latest/user_guides/source_compile.html#id13) -4. [Windows](https://paddle-lite.readthedocs.io/zh/latest/demo_guides/x86.html#windows) +4. [Windows](https://paddle-lite.readthedocs.io/zh/latest/demo_guides/x86.html#id4) ### 1.2 准备预测库 @@ -84,7 +84,7 @@ Paddle-Lite 提供了多种策略来自动优化原始的模型,其中包括 |模型简介|检测模型|识别模型|Paddle-Lite版本| |-|-|-|-| -|超轻量级中文OCR opt优化模型|[下载地址](https://paddleocr.bj.bcebos.com/deploy/lite/ch_det_mv3_db_opt.nb)|[下载地址](https://paddleocr.bj.bcebos.com/deploy/lite/ch_rec_mv3_crnn_opt.nb)|2.6.1| +|超轻量级中文OCR opt优化模型|[下载地址](https://paddleocr.bj.bcebos.com/deploy/lite/ch_det_mv3_db_opt.nb)|[下载地址](https://paddleocr.bj.bcebos.com/deploy/lite/ch_rec_mv3_crnn_opt.nb)|develop| 如果直接使用上述表格中的模型进行部署,可略过下述步骤,直接阅读 [2.2节](#2.2与手机联调)。 diff --git a/deploy/lite/readme_en.md b/deploy/lite/readme_en.md index a8c9f604..6110e646 100644 --- a/deploy/lite/readme_en.md +++ b/deploy/lite/readme_en.md @@ -17,7 +17,7 @@ deployment solutions for end-side deployment issues. [build for Docker](https://paddle-lite.readthedocs.io/zh/latest/user_guides/source_compile.html#docker) [build for Linux](https://paddle-lite.readthedocs.io/zh/latest/user_guides/source_compile.html#android) [build for MAC OS](https://paddle-lite.readthedocs.io/zh/latest/user_guides/source_compile.html#id13) -[build for windows](https://paddle-lite.readthedocs.io/zh/latest/demo_guides/x86.html#windows) +[build for windows](https://paddle-lite.readthedocs.io/zh/latest/demo_guides/x86.html#id4) ## 3. Download prebuild library for android and ios diff --git a/ppocr/modeling/backbones/rec_mobilenet_v3.py b/ppocr/modeling/backbones/rec_mobilenet_v3.py index 506209cc..650b2d59 100755 --- a/ppocr/modeling/backbones/rec_mobilenet_v3.py +++ b/ppocr/modeling/backbones/rec_mobilenet_v3.py @@ -78,7 +78,7 @@ class MobileNetV3(): supported_scale = [0.35, 0.5, 0.75, 1.0, 1.25] assert self.scale in supported_scale, \ - "supported scale are {} but input scale is {}".format(supported_scale, scale) + "supported scale are {} but input scale is {}".format(supported_scale, self.scale) def __call__(self, input): scale = self.scale From 8a11d97da8dbb28792e649b4f6302fe9e4bb3649 Mon Sep 17 00:00:00 2001 From: LDOUBLEV Date: Thu, 23 Jul 2020 11:12:35 +0800 Subject: [PATCH 25/26] typo --- deploy/lite/readme_en.md | 2 +- ppocr/modeling/backbones/rec_mobilenet_v3.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/lite/readme_en.md b/deploy/lite/readme_en.md index 6110e646..1efbba36 100644 --- a/deploy/lite/readme_en.md +++ b/deploy/lite/readme_en.md @@ -155,7 +155,7 @@ demo/cxx/ocr/ |-- debug/ | |--ch_det_mv3_db_opt.nb Detection model | |--ch_rec_mv3_crnn_opt.nb Recognition model -| |--11.jpg image for OCR +| |--11.jpg Image for OCR | |--ppocr_keys_v1.txt Dictionary file | |--libpaddle_light_api_shared.so C++ .so file | |--config.txt Config file diff --git a/ppocr/modeling/backbones/rec_mobilenet_v3.py b/ppocr/modeling/backbones/rec_mobilenet_v3.py index 650b2d59..e5040642 100755 --- a/ppocr/modeling/backbones/rec_mobilenet_v3.py +++ b/ppocr/modeling/backbones/rec_mobilenet_v3.py @@ -78,7 +78,7 @@ class MobileNetV3(): supported_scale = [0.35, 0.5, 0.75, 1.0, 1.25] assert self.scale in supported_scale, \ - "supported scale are {} but input scale is {}".format(supported_scale, self.scale) + "supported scales are {} but input scale is {}".format(supported_scale, self.scale) def __call__(self, input): scale = self.scale From f45946dc83b7d54b1061d456d950983928583d94 Mon Sep 17 00:00:00 2001 From: LDOUBLEV Date: Thu, 23 Jul 2020 15:35:23 +0800 Subject: [PATCH 26/26] add hint when install shapely on win --- doc/doc_ch/installation.md | 3 +++ doc/doc_en/installation_en.md | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/doc/doc_ch/installation.md b/doc/doc_ch/installation.md index 4b75e21b..7a51c561 100644 --- a/doc/doc_ch/installation.md +++ b/doc/doc_ch/installation.md @@ -80,3 +80,6 @@ git clone https://gitee.com/paddlepaddle/PaddleOCR cd PaddleOCR pip3 install -r requirments.txt ``` + +注意,windows环境下,建议从[这里](https://www.lfd.uci.edu/~gohlke/pythonlibs/#shapely)下载shapely安装包完成安装, +直接通过pip安装的shapely库可能出现`[winRrror 126] 找不到指定模块的问题`。 diff --git a/doc/doc_en/installation_en.md b/doc/doc_en/installation_en.md index 585f9d43..9e4df74f 100644 --- a/doc/doc_en/installation_en.md +++ b/doc/doc_en/installation_en.md @@ -82,3 +82,9 @@ git clone https://gitee.com/paddlepaddle/PaddleOCR cd PaddleOCR pip3 install -r requirments.txt ``` + +If you getting this error `OSError: [WinError 126] The specified module could not be found` when you install shapely on windows. + +Please try to download Shapely whl file using [http://www.lfd.uci.edu/~gohlke/pythonlibs/#shapely](http://www.lfd.uci.edu/~gohlke/pythonlibs/#shapely). + +Reference: [Solve shapely installation on windows](https://stackoverflow.com/questions/44398265/install-shapely-oserror-winerror-126-the-specified-module-could-not-be-found)