{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "\n",
    "# 1. 预测部署简介与总览\n",
    "\n",
    "\n",
    "本章主要介绍PP-OCRv2系统的高性能推理方法、服务化部署方法以及端侧部署方法。通过本章的学习，您可以学习到：\n",
    "\n",
    "* 根据不同的场景挑选合适的预测部署方法\n",
    "* PP-OCRv2系列模型在不同场景下的推理方法\n",
    "* Paddle Inference、Paddle Serving、Paddle Lite的推理部署开发方法\n",
    "\n",
    "## 1.1 简介\n",
    "\n",
    "在前面几个章节中，我们通过模型训练的方法，得到了训练好的模型，在使用它去预测的时候，我们首先需要定义好模型，然后加载训练好的模型，再将预处理之后的数据送进网络中进行预测、后处理，得到最终的结果。使用这种方法去进行预测，调试方便，但是预测效率比较低下。\n",
    "\n",
    "针对上面的问题，对于训练得到的模型，一般有下面2种离线预测的方式。\n",
    "\n",
    "1. 基于训练引擎推理，也就是和训练使用同一套引擎，它调试方便，便于我们迅速定位问题，验证正确性。多为Python语言。\n",
    "2. 基于预测引擎推理，将训练得到的模型进行转换，去掉与推理无关的部分，使用这种方法可以加速预测。多为Python语言或C++。\n",
    "\n",
    "二者具体的区别如下所示。\n",
    "\n",
    "<center>\n",
    "\n",
    "|      | 基于训练引擎推理    | 基于预测引擎推理    |\n",
    "|:------:|:------|:------|\n",
    "| 特点   | 1. 和训练使用同一套引擎</br>2. 预测时需要定义网络模型</br>3. 不适合系统集成      | 1. 需要转换模型，去掉与推理无关的部分</br>2. **预测时无需定义网络模型**</br>3. 适合系统集成 |\n",
    "| 编程语言 | 多为Python                                     | Python或者C++                     |\n",
    "| 预测步骤 | 1. Python端定义网络结构</br>2. 准备输入数据</br>3. 加载训练模型</br>4. 执行预测 | 1. 准备输入数据</br>2. 加载模型结构和模型参数</br>3.执行预测 |\n",
    "\n",
    "</center>\n",
    "\n",
    "在实际离线预测部署中，更推荐基于预测引擎进行推理。\n",
    "\n",
    "从应用场景来看，飞桨针对不同应用场景，提供了下面一些推理部署方案。\n",
    "\n",
    "<div align=\"center\">\n",
    "<img src=\"https://ai-studio-static-online.cdn.bcebos.com/d95a9b662f944af589cf3934b7012f54bfb1ef610c0447568712618fdb6216a2\"  width = \"1200\" />\n",
    "</div>\n",
    "<center>飞桨的不同部署方案</center>\n",
    "\n",
    "具体地，PaddleOCR 针对不同应用场景，提供了三种预测部署方案。\n",
    "\n",
    "* Inference的离线预测，这种方式主要应用在对预测响应的及时性要求不高，特别是需要大量图片预测的场景。像文档电子化、广告信息提取等。虽然不能及时响应预测请求，但是没有网络延时，计算效率比较高，数据安全性很高。\n",
    "* Serving服务化部署，这种方式主要应用在对预测响应的及时性要求很高的场景，像商业化OCR的API接口、实时拍照翻译、拍题等场景。虽然这种方式能及时对预测需求及时响应，但是网络耗时开销比较大，GPU利用率往往不高，而且存在数据安全风险。\n",
    "* Lite端侧部署，这种方式主要希望模型部署到手机、机器人等端侧设备上，主要考虑部署方便和数据安全性，像手机APP里面身份证识别、银行卡识别，工业应用场景的仪表监控识别等。这种方法，对OCR模型的大小比较敏感。虽然没有网络延时，数据安全性很高，但是由于算力限制，预测效率不高。\n",
    "\n",
    "本章基于PP-OCRv2，介绍文本检测、识别以及系统串联预测推理与部署过程。\n",
    "\n",
    "## 1.2 环境准备\n",
    "\n",
    "体验本章节内容需要首先下载PaddleOCR代码，安装相关依赖，具体命令如下。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cloning into 'PaddleOCR'...\n",
      "remote: Enumerating objects: 2335, done.\u001b[K\n",
      "remote: Counting objects: 100% (2335/2335), done.\u001b[K\n",
      "remote: Compressing objects: 100% (937/937), done.\u001b[K\n",
      "remote: Total 27956 (delta 1569), reused 2078 (delta 1382), pack-reused 25621\u001b[K\n",
      "Receiving objects: 100% (27956/27956), 245.96 MiB | 4.68 MiB/s, done.\n",
      "Resolving deltas: 100% (19430/19430), done.\n",
      "Checking connectivity... done.\n",
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple\n",
      "Collecting pip\n",
      "\u001b[?25l  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/a4/6d/6463d49a933f547439d6b5b98b46af8742cc03ae83543e4d7688c2420f8b/pip-21.3.1-py3-none-any.whl (1.7MB)\n",
      "\u001b[K     |████████████████████████████████| 1.7MB 17.9MB/s eta 0:00:01\n",
      "\u001b[?25hInstalling collected packages: pip\n",
      "  Found existing installation: pip 19.2.3\n",
      "    Uninstalling pip-19.2.3:\n",
      "      Successfully uninstalled pip-19.2.3\n",
      "Successfully installed pip-21.3.1\n",
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple\n",
      "Collecting shapely\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/ae/20/33ce377bd24d122a4d54e22ae2c445b9b1be8240edb50040b40add950cd9/Shapely-1.8.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl (1.1 MB)\n",
      "     |████████████████████████████████| 1.1 MB 27.3 MB/s            \n",
      "\u001b[?25hCollecting scikit-image\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/9a/44/8f8c7f9c9de7fde70587a656d7df7d056e6f05192a74491f7bc074a724d0/scikit_image-0.19.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (13.3 MB)\n",
      "     |████████████████████████████████| 13.3 MB 74.2 MB/s            \n",
      "\u001b[?25hCollecting imgaug==0.4.0\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/66/b1/af3142c4a85cba6da9f4ebb5ff4e21e2616309552caca5e8acefe9840622/imgaug-0.4.0-py2.py3-none-any.whl (948 kB)\n",
      "     |████████████████████████████████| 948 kB 53.5 MB/s            \n",
      "\u001b[?25hCollecting pyclipper\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/c5/fa/2c294127e4f88967149a68ad5b3e43636e94e3721109572f8f17ab15b772/pyclipper-1.3.0.post2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl (603 kB)\n",
      "     |████████████████████████████████| 603 kB 55.1 MB/s            \n",
      "\u001b[?25hCollecting lmdb\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/2e/dd/ada2fd91cd7832979069c556607903f274470c3d3d2274e0a848908272e8/lmdb-1.2.1-cp37-cp37m-manylinux2010_x86_64.whl (299 kB)\n",
      "     |████████████████████████████████| 299 kB 59.7 MB/s            \n",
      "\u001b[?25hRequirement already satisfied: tqdm in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from -r requirements.txt (line 6)) (4.27.0)\n",
      "Requirement already satisfied: numpy in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from -r requirements.txt (line 7)) (1.20.3)\n",
      "Requirement already satisfied: visualdl in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from -r requirements.txt (line 8)) (2.2.0)\n",
      "Collecting python-Levenshtein\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/2a/dc/97f2b63ef0fa1fd78dcb7195aca577804f6b2b51e712516cc0e902a9a201/python-Levenshtein-0.12.2.tar.gz (50 kB)\n",
      "     |████████████████████████████████| 50 kB 16.0 MB/s            \n",
      "\u001b[?25h  Preparing metadata (setup.py) ... \u001b[?25ldone\n",
      "\u001b[?25hCollecting opencv-contrib-python==4.4.0.46\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/08/51/1e0a206dd5c70fea91084e6f43979dc13e8eb175760cc7a105083ec3eb68/opencv_contrib_python-4.4.0.46-cp37-cp37m-manylinux2014_x86_64.whl (55.7 MB)\n",
      "     |████████████████████████████████| 55.7 MB 49 kB/s             \n",
      "\u001b[?25hRequirement already satisfied: cython in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from -r requirements.txt (line 11)) (0.29)\n",
      "Collecting lxml\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/7b/01/16a9b80c8ce4339294bb944f08e157dbfcfbb09ba9031bde4ddf7e3e5499/lxml-4.7.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl (6.4 MB)\n",
      "     |████████████████████████████████| 6.4 MB 5.1 MB/s            \n",
      "\u001b[?25hCollecting premailer\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/b1/07/4e8d94f94c7d41ca5ddf8a9695ad87b888104e2fd41a35546c1dc9ca74ac/premailer-3.10.0-py2.py3-none-any.whl (19 kB)\n",
      "Requirement already satisfied: openpyxl in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from -r requirements.txt (line 14)) (3.0.5)\n",
      "Collecting fasttext==0.9.1\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/10/61/2e01f1397ec533756c1d893c22d9d5ed3fce3a6e4af1976e0d86bb13ea97/fasttext-0.9.1.tar.gz (57 kB)\n",
      "     |████████████████████████████████| 57 kB 12.8 MB/s            \n",
      "\u001b[?25h  Preparing metadata (setup.py) ... \u001b[?25ldone\n",
      "\u001b[?25hRequirement already satisfied: matplotlib in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from imgaug==0.4.0->-r requirements.txt (line 3)) (2.2.3)\n",
      "Requirement already satisfied: six in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from imgaug==0.4.0->-r requirements.txt (line 3)) (1.15.0)\n",
      "Requirement already satisfied: opencv-python in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from imgaug==0.4.0->-r requirements.txt (line 3)) (4.1.1.26)\n",
      "Requirement already satisfied: imageio in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from imgaug==0.4.0->-r requirements.txt (line 3)) (2.6.1)\n",
      "Requirement already satisfied: scipy in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from imgaug==0.4.0->-r requirements.txt (line 3)) (1.6.3)\n",
      "Requirement already satisfied: Pillow in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from imgaug==0.4.0->-r requirements.txt (line 3)) (7.1.2)\n",
      "Collecting pybind11>=2.2\n",
      "  Using cached https://pypi.tuna.tsinghua.edu.cn/packages/a8/3b/fc246e1d4c7547a7a07df830128e93c6215e9b93dcb118b2a47a70726153/pybind11-2.8.1-py2.py3-none-any.whl (208 kB)\n",
      "Requirement already satisfied: setuptools>=0.7.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from fasttext==0.9.1->-r requirements.txt (line 15)) (56.2.0)\n",
      "Collecting PyWavelets>=1.1.1\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/a1/9c/564511b6e1c4e1d835ed2d146670436036960d09339a8fa2921fe42dad08/PyWavelets-1.2.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl (6.1 MB)\n",
      "     |████████████████████████████████| 6.1 MB 49.8 MB/s            \n",
      "\u001b[?25hRequirement already satisfied: packaging>=20.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from scikit-image->-r requirements.txt (line 2)) (20.9)\n",
      "Collecting tifffile>=2019.7.26\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/d8/38/85ae5ed77598ca90558c17a2f79ddaba33173b31cf8d8f545d34d9134f0d/tifffile-2021.11.2-py3-none-any.whl (178 kB)\n",
      "     |████████████████████████████████| 178 kB 56.8 MB/s            \n",
      "\u001b[?25hRequirement already satisfied: networkx>=2.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from scikit-image->-r requirements.txt (line 2)) (2.4)\n",
      "Requirement already satisfied: flask>=1.1.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->-r requirements.txt (line 8)) (1.1.1)\n",
      "Requirement already satisfied: pre-commit in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->-r requirements.txt (line 8)) (1.21.0)\n",
      "Requirement already satisfied: shellcheck-py in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->-r requirements.txt (line 8)) (0.7.1.1)\n",
      "Requirement already satisfied: protobuf>=3.11.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->-r requirements.txt (line 8)) (3.14.0)\n",
      "Requirement already satisfied: bce-python-sdk in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->-r requirements.txt (line 8)) (0.8.53)\n",
      "Requirement already satisfied: requests in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->-r requirements.txt (line 8)) (2.22.0)\n",
      "Requirement already satisfied: pandas in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->-r requirements.txt (line 8)) (1.1.5)\n",
      "Requirement already satisfied: Flask-Babel>=1.0.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->-r requirements.txt (line 8)) (1.0.0)\n",
      "Requirement already satisfied: flake8>=3.7.9 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->-r requirements.txt (line 8)) (3.8.2)\n",
      "Collecting cssutils\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/24/c4/9db28fe567612896d360ab28ad02ee8ae107d0e92a22db39affd3fba6212/cssutils-2.3.0-py3-none-any.whl (404 kB)\n",
      "     |████████████████████████████████| 404 kB 43.6 MB/s            \n",
      "\u001b[?25hCollecting cssselect\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/3b/d4/3b5c17f00cce85b9a1e6f91096e1cc8e8ede2e1be8e96b87ce1ed09e92c5/cssselect-1.1.0-py2.py3-none-any.whl (16 kB)\n",
      "Requirement already satisfied: cachetools in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from premailer->-r requirements.txt (line 13)) (4.0.0)\n",
      "Requirement already satisfied: jdcal in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from openpyxl->-r requirements.txt (line 14)) (1.4.1)\n",
      "Requirement already satisfied: et-xmlfile in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from openpyxl->-r requirements.txt (line 14)) (1.0.1)\n",
      "Requirement already satisfied: importlib-metadata in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flake8>=3.7.9->visualdl->-r requirements.txt (line 8)) (0.23)\n",
      "Requirement already satisfied: mccabe<0.7.0,>=0.6.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flake8>=3.7.9->visualdl->-r requirements.txt (line 8)) (0.6.1)\n",
      "Requirement already satisfied: pycodestyle<2.7.0,>=2.6.0a1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flake8>=3.7.9->visualdl->-r requirements.txt (line 8)) (2.6.0)\n",
      "Requirement already satisfied: pyflakes<2.3.0,>=2.2.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flake8>=3.7.9->visualdl->-r requirements.txt (line 8)) (2.2.0)\n",
      "Requirement already satisfied: click>=5.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flask>=1.1.1->visualdl->-r requirements.txt (line 8)) (7.0)\n",
      "Requirement already satisfied: itsdangerous>=0.24 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flask>=1.1.1->visualdl->-r requirements.txt (line 8)) (1.1.0)\n",
      "Requirement already satisfied: Jinja2>=2.10.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flask>=1.1.1->visualdl->-r requirements.txt (line 8)) (2.11.0)\n",
      "Requirement already satisfied: Werkzeug>=0.15 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flask>=1.1.1->visualdl->-r requirements.txt (line 8)) (0.16.0)\n",
      "Requirement already satisfied: pytz in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from Flask-Babel>=1.0.0->visualdl->-r requirements.txt (line 8)) (2019.3)\n",
      "Requirement already satisfied: Babel>=2.3 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from Flask-Babel>=1.0.0->visualdl->-r requirements.txt (line 8)) (2.8.0)\n",
      "Requirement already satisfied: decorator>=4.3.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from networkx>=2.2->scikit-image->-r requirements.txt (line 2)) (4.4.2)\n",
      "Requirement already satisfied: pyparsing>=2.0.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from packaging>=20.0->scikit-image->-r requirements.txt (line 2)) (2.4.2)\n",
      "Requirement already satisfied: future>=0.6.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from bce-python-sdk->visualdl->-r requirements.txt (line 8)) (0.18.0)\n",
      "Requirement already satisfied: pycryptodome>=3.8.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from bce-python-sdk->visualdl->-r requirements.txt (line 8)) (3.9.9)\n",
      "Requirement already satisfied: python-dateutil>=2.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from matplotlib->imgaug==0.4.0->-r requirements.txt (line 3)) (2.8.0)\n",
      "Requirement already satisfied: cycler>=0.10 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from matplotlib->imgaug==0.4.0->-r requirements.txt (line 3)) (0.10.0)\n",
      "Requirement already satisfied: kiwisolver>=1.0.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from matplotlib->imgaug==0.4.0->-r requirements.txt (line 3)) (1.1.0)\n",
      "Requirement already satisfied: identify>=1.0.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->-r requirements.txt (line 8)) (1.4.10)\n",
      "Requirement already satisfied: nodeenv>=0.11.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->-r requirements.txt (line 8)) (1.3.4)\n",
      "Requirement already satisfied: virtualenv>=15.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->-r requirements.txt (line 8)) (16.7.9)\n",
      "Requirement already satisfied: pyyaml in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->-r requirements.txt (line 8)) (5.1.2)\n",
      "Requirement already satisfied: toml in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->-r requirements.txt (line 8)) (0.10.0)\n",
      "Requirement already satisfied: aspy.yaml in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->-r requirements.txt (line 8)) (1.3.0)\n",
      "Requirement already satisfied: cfgv>=2.0.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->-r requirements.txt (line 8)) (2.0.1)\n",
      "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from requests->visualdl->-r requirements.txt (line 8)) (3.0.4)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from requests->visualdl->-r requirements.txt (line 8)) (2019.9.11)\n",
      "Requirement already satisfied: idna<2.9,>=2.5 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from requests->visualdl->-r requirements.txt (line 8)) (2.8)\n",
      "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from requests->visualdl->-r requirements.txt (line 8)) (1.25.6)\n",
      "Requirement already satisfied: MarkupSafe>=0.23 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from Jinja2>=2.10.1->flask>=1.1.1->visualdl->-r requirements.txt (line 8)) (1.1.1)\n",
      "Requirement already satisfied: zipp>=0.5 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from importlib-metadata->flake8>=3.7.9->visualdl->-r requirements.txt (line 8)) (3.6.0)\n",
      "Building wheels for collected packages: fasttext, python-Levenshtein\n",
      "  Building wheel for fasttext (setup.py) ... \u001b[?25ldone\n",
      "\u001b[?25h  Created wheel for fasttext: filename=fasttext-0.9.1-cp37-cp37m-linux_x86_64.whl size=2585528 sha256=e9fa045840a7c64a81fede292ad670651aa5fe46380135f54ee64b17d9030594\n",
      "  Stored in directory: /home/aistudio/.cache/pip/wheels/a1/cb/b3/a25a8ce16c1a4ff102c1e40d6eaa4dfc9d5695b92d57331b36\n",
      "  Building wheel for python-Levenshtein (setup.py) ... \u001b[?25ldone\n",
      "\u001b[?25h  Created wheel for python-Levenshtein: filename=python_Levenshtein-0.12.2-cp37-cp37m-linux_x86_64.whl size=171687 sha256=8acb827b504424dfde1dae12b21c2d0ebbc5df8b46d73086c5c14cae7bb908fd\n",
      "  Stored in directory: /home/aistudio/.cache/pip/wheels/38/b9/a4/3729726160fb103833de468adb5ce019b58543ae41d0b0e446\n",
      "Successfully built fasttext python-Levenshtein\n",
      "Installing collected packages: tifffile, PyWavelets, shapely, scikit-image, pybind11, lxml, cssutils, cssselect, python-Levenshtein, pyclipper, premailer, opencv-contrib-python, lmdb, imgaug, fasttext\n",
      "Successfully installed PyWavelets-1.2.0 cssselect-1.1.0 cssutils-2.3.0 fasttext-0.9.1 imgaug-0.4.0 lmdb-1.2.1 lxml-4.7.1 opencv-contrib-python-4.4.0.46 premailer-3.10.0 pybind11-2.8.1 pyclipper-1.3.0.post2 python-Levenshtein-0.12.2 scikit-image-0.19.1 shapely-1.8.0 tifffile-2021.11.2\n",
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple\n",
      "Collecting paddlenlp==2.2.1\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/dd/cb/f15e5406718079a201b869b46705ef0882be2ffb6932472e44efc3d16a75/paddlenlp-2.2.1-py3-none-any.whl (1.0 MB)\n",
      "     |████████████████████████████████| 1.0 MB 11.9 MB/s            \n",
      "\u001b[?25hRequirement already satisfied: multiprocess in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddlenlp==2.2.1) (0.70.11.1)\n",
      "Requirement already satisfied: seqeval in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddlenlp==2.2.1) (1.2.2)\n",
      "Requirement already satisfied: h5py in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddlenlp==2.2.1) (2.9.0)\n",
      "Requirement already satisfied: colorlog in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddlenlp==2.2.1) (4.1.0)\n",
      "Requirement already satisfied: colorama in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddlenlp==2.2.1) (0.4.4)\n",
      "Requirement already satisfied: jieba in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddlenlp==2.2.1) (0.42.1)\n",
      "Requirement already satisfied: six in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from h5py->paddlenlp==2.2.1) (1.15.0)\n",
      "Requirement already satisfied: numpy>=1.7 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from h5py->paddlenlp==2.2.1) (1.20.3)\n",
      "Requirement already satisfied: dill>=0.3.3 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from multiprocess->paddlenlp==2.2.1) (0.3.3)\n",
      "Requirement already satisfied: scikit-learn>=0.21.3 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from seqeval->paddlenlp==2.2.1) (0.24.2)\n",
      "Requirement already satisfied: scipy>=0.19.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from scikit-learn>=0.21.3->seqeval->paddlenlp==2.2.1) (1.6.3)\n",
      "Requirement already satisfied: joblib>=0.11 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from scikit-learn>=0.21.3->seqeval->paddlenlp==2.2.1) (0.14.1)\n",
      "Requirement already satisfied: threadpoolctl>=2.0.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from scikit-learn>=0.21.3->seqeval->paddlenlp==2.2.1) (2.1.0)\n",
      "Installing collected packages: paddlenlp\n",
      "  Attempting uninstall: paddlenlp\n",
      "    Found existing installation: paddlenlp 2.1.1\n",
      "    Uninstalling paddlenlp-2.1.1:\n",
      "      Successfully uninstalled paddlenlp-2.1.1\n",
      "Successfully installed paddlenlp-2.2.1\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "os.chdir(\"/home/aistudio\")\n",
    "# 下载代码\n",
    "!git clone https://gitee.com/paddlepaddle/PaddleOCR.git\n",
    "os.chdir(\"/home/aistudio/PaddleOCR\")\n",
    "# 安装运行所需要的whl包\n",
    "!pip install -U pip\n",
    "!pip install -r requirements.txt\n",
    "# VQA任务中需要用到该库\n",
    "!pip install paddlenlp==2.2.1\n",
    "\n",
    "# 导入一些库\n",
    "import cv2\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import os"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "\n",
    "# 2. 基于Paddle Inference的python推理\n",
    "\n",
    "## 2.1 简介\n",
    "\n",
    "在项目中，模型的推理性能直接影响项目成本，因此我们期望一个训练好的模型的模型可以拥有更快的推理速度。直接基于训练引擎进行预测，模型中包含与训练相关的算子，因此**效率一般较低**；而且需要定义模型，**难以与训练代码解耦**。Paddle Inference应运而生。它是飞桨的原生推理库，作用于服务器端和云端，提供高性能的推理能力。由于能力直接基于飞桨的训练算子，因此Paddle Inference 可以通用支持飞桨训练出的所有模型。\n",
    "\n",
    "考虑到大家的使用场景差异很大，Paddle Inference针对不同平台不同的应用场景进行了深度的适配优化，做到高吞吐、低时延，保证了飞桨模型在服务器端即训即用，快速部署。\n",
    "\n",
    "本章主要介绍基于Paddle Inference的**PP-OCRv2**预测推理过程，更多关于Paddle Inference的介绍可以参考：[Paddle Inference 介绍](https://paddleinference.paddlepaddle.org.cn/product_introduction/inference_intro.html)。\n",
    "\n",
    "在基于Paddle Inference进行模型推理时，一般有以下几个步骤。\n",
    "\n",
    "<div align=\"center\">\n",
    "<img src=\"https://ai-studio-static-online.cdn.bcebos.com/18090cbc0733401caeb868f7bf7759436771ba71bce444a8a4ff5dbc5eece03c\"  width = \"600\" />\n",
    "</div>\n",
    "<center>Paddle Inference推理流程</center>\n",
    "\n",
    "PP-OCRv2系统包含**文字检测、方向分类器和文字识别**3个模型，下面分别介绍这3个模型基于Paddle Inference的推理过程。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "\n",
    "## 2.2 PP-OCRv2文字检测模型推理\n",
    "\n",
    "PaddleOCR中，在基于文字检测模型进行推理时，需要通过参数`image_dir`指定单张图像或者图像集合的路径、参数`det_model_dir`, 指定检测的 `inference` 模型路径。\n",
    "\n",
    "下面进行最新的超轻量文本检测模型推理实战，更多的模型和使用方法请参考[文本检测预测教程](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.4/doc/doc_ch/inference_ppocr.md)。\n",
    "\n",
    "更多等算法超参数的介绍可以参考[PaddleOCR Inference推理相关参数介绍](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.4/doc/doc_ch/inference.md#%E5%85%AD%E5%8F%82%E6%95%B0%E8%A7%A3%E9%87%8A)。\n",
    "\n",
    "\n",
    "### 2.2.1 准备数据和环境\n",
    "\n",
    "在最开始已经安装好了Paddle以及相应的依赖，这里环境已经准备好了。\n",
    "\n",
    "检测示例数据在`doc/imgs`文件夹下面，部分数据如下所示。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "00006737.jpg  00056221.jpg  00111002.jpg  1.jpg\t\tjapan_1.jpg\r\n",
      "00009282.jpg  00057937.jpg  00207393.jpg  french_0.jpg\tjapan_2.jpg\r\n",
      "00015504.jpg  00059985.jpg  11.jpg\t  ger_1.jpg\tkorean_1.jpg\r\n",
      "00018069.jpg  00077949.jpg  12.jpg\t  ger_2.jpg\tmodel_prod_flow_ch.png\r\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 433396 characters]",
      "text/plain": [
       "<Figure size 1080x432 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 切换目录\n",
    "os.chdir(\"/home/aistudio/PaddleOCR\")\n",
    "\n",
    "# 查看数据\n",
    "!ls doc/imgs/\n",
    "\n",
    "# 选择2张图像可视化\n",
    "img1 = cv2.imread(\"doc/imgs/00006737.jpg\")\n",
    "img2 = cv2.imread(\"doc/imgs/00056221.jpg\")\n",
    "plt.figure(figsize=(15, 6))\n",
    "plt.subplot(1, 2, 1)\n",
    "plt.imshow(img1[:,:,::-1])\n",
    "plt.subplot(1, 2, 2)\n",
    "plt.imshow(img2[:,:,::-1])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### 2.2.2 准备推理模型\n",
    "\n",
    "下载推理模型并解压，放在`inference`目录下面。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2021-12-25 14:55:13--  https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_infer.tar\n",
      "Resolving paddleocr.bj.bcebos.com (paddleocr.bj.bcebos.com)... 100.67.200.6\n",
      "Connecting to paddleocr.bj.bcebos.com (paddleocr.bj.bcebos.com)|100.67.200.6|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 3190272 (3.0M) [application/x-tar]\n",
      "Saving to: ‘ch_PP-OCRv2_det_infer.tar’\n",
      "\n",
      "ch_PP-OCRv2_det_inf 100%[===================>]   3.04M  --.-KB/s    in 0.07s   \n",
      "\n",
      "2021-12-25 14:55:13 (42.2 MB/s) - ‘ch_PP-OCRv2_det_infer.tar’ saved [3190272/3190272]\n",
      "\n",
      "inference/ch_PP-OCRv2_det_infer\n",
      "├── [2.2M]  inference.pdiparams\n",
      "├── [ 23K]  inference.pdiparams.info\n",
      "└── [845K]  inference.pdmodel\n",
      "\n",
      "0 directories, 3 files\n"
     ]
    }
   ],
   "source": [
    "# 下载模型\n",
    "!mkdir inference\n",
    "!cd inference && wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_infer.tar -O ch_PP-OCRv2_det_infer.tar && tar -xf ch_PP-OCRv2_det_infer.tar\n",
    "!tree -h inference/ch_PP-OCRv2_det_infer"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "* 如果您希望导出自己训练得到的模型，使用Paddle Inference部署，那么可以使用下面的命令将预训练模型使用动转静的方法，转化为推理模型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2021-12-25 14:55:21--  https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_distill_train.tar\n",
      "Resolving paddleocr.bj.bcebos.com (paddleocr.bj.bcebos.com)... 100.67.200.6\n",
      "Connecting to paddleocr.bj.bcebos.com (paddleocr.bj.bcebos.com)|100.67.200.6|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 63830016 (61M) [application/x-tar]\n",
      "Saving to: ‘ch_PP-OCRv2_det_distill_train.tar’\n",
      "\n",
      "ch_PP-OCRv2_det_dis 100%[===================>]  60.87M  81.4MB/s    in 0.7s    \n",
      "\n",
      "2021-12-25 14:55:22 (81.4 MB/s) - ‘ch_PP-OCRv2_det_distill_train.tar’ saved [63830016/63830016]\n",
      "\n",
      "W1225 14:55:24.746377  1078 device_context.cc:447] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 10.1, Runtime API Version: 10.1\n",
      "W1225 14:55:24.749907  1078 device_context.cc:465] device: 0, cuDNN Version: 7.6.\n",
      "[2021/12/25 14:55:30] root INFO: load pretrain successful from ch_PP-OCRv2_det_distill_train/best_accuracy\n",
      "[2021/12/25 14:55:31] root INFO: inference model is saved to ./my_model/Teacher/inference\n",
      "[2021/12/25 14:55:33] root INFO: inference model is saved to ./my_model/Student/inference\n",
      "[2021/12/25 14:55:34] root INFO: inference model is saved to ./my_model/Student2/inference\n",
      "my_model\n",
      "├── [4.0K]  Student\n",
      "│   ├── [2.2M]  inference.pdiparams\n",
      "│   ├── [ 23K]  inference.pdiparams.info\n",
      "│   └── [961K]  inference.pdmodel\n",
      "├── [4.0K]  Student2\n",
      "│   ├── [2.2M]  inference.pdiparams\n",
      "│   ├── [ 23K]  inference.pdiparams.info\n",
      "│   └── [962K]  inference.pdmodel\n",
      "└── [4.0K]  Teacher\n",
      "    ├── [ 47M]  inference.pdiparams\n",
      "    ├── [ 12K]  inference.pdiparams.info\n",
      "    └── [568K]  inference.pdmodel\n",
      "\n",
      "3 directories, 9 files\n"
     ]
    }
   ],
   "source": [
    "# 参考代码\n",
    "# https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.4/tools/export_model.py\n",
    "# 下载预训练模型\n",
    "!wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_distill_train.tar && tar -xf ch_PP-OCRv2_det_distill_train.tar && rm ch_PP-OCRv2_det_distill_train.tar\n",
    "# 导出推理模型\n",
    "!python tools/export_model.py -c configs/det/ch_PP-OCRv2/ch_PP-OCRv2_det_cml.yml \\\n",
    "    -o Global.pretrained_model=\"ch_PP-OCRv2_det_distill_train/best_accuracy\" \\\n",
    "    Global.save_inference_dir=\"./my_model\"\n",
    "# PP-OCRv2检测模型包含3个子网络：教师、学生、学生2，因此导出时，包含3个子文件，实际推理时，使用其中1个学生网络进行推理即可\n",
    "!tree -h my_model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### 2.2.3 文本检测功能初探\n",
    "\n",
    "我们先来看看加载加载推理模型预测得到的结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2021/12/25 14:56:01] root INFO: 00018069.jpg\t[[[378, 249], [411, 252], [409, 266], [377, 265]], [[300, 250], [344, 250], [344, 265], [300, 265]], [[233, 250], [268, 250], [268, 265], [233, 265]], [[101, 249], [184, 249], [184, 266], [101, 266]], [[25, 250], [52, 250], [52, 266], [25, 266]], [[375, 233], [409, 233], [409, 247], [375, 247]], [[285, 233], [362, 233], [362, 247], [285, 247]], [[234, 233], [269, 233], [269, 247], [234, 247]], [[24, 234], [53, 234], [53, 247], [24, 247]], [[101, 230], [184, 230], [184, 248], [101, 248]], [[23, 214], [51, 214], [51, 229], [23, 229]], [[378, 213], [410, 213], [410, 228], [378, 228]], [[295, 211], [348, 214], [347, 229], [294, 226]], [[231, 213], [268, 213], [268, 228], [231, 228]], [[100, 212], [185, 212], [185, 229], [100, 229]], [[309, 195], [338, 195], [338, 209], [309, 209]], [[231, 194], [268, 194], [268, 209], [231, 209]], [[23, 194], [51, 194], [51, 210], [23, 210]], [[378, 193], [409, 193], [409, 209], [378, 209]], [[99, 193], [188, 193], [188, 208], [99, 208]], [[376, 175], [413, 175], [413, 190], [376, 190]], [[22, 175], [52, 175], [52, 192], [22, 192]], [[288, 173], [360, 173], [360, 191], [288, 191]], [[237, 174], [264, 174], [264, 190], [237, 190]], [[100, 173], [185, 173], [185, 191], [100, 191]], [[22, 156], [52, 156], [52, 172], [22, 172]], [[284, 154], [358, 154], [358, 172], [284, 172]], [[235, 155], [267, 155], [267, 171], [235, 171]], [[119, 155], [167, 155], [167, 170], [119, 170]], [[378, 138], [410, 135], [412, 152], [379, 155]], [[294, 136], [357, 136], [357, 153], [294, 153]], [[232, 137], [271, 137], [271, 152], [232, 152]], [[118, 137], [166, 137], [166, 151], [118, 151]], [[22, 137], [52, 137], [52, 152], [22, 152]], [[379, 119], [406, 119], [406, 135], [379, 135]], [[229, 118], [268, 118], [268, 134], [229, 134]], [[23, 118], [52, 118], [52, 134], [23, 134]], [[294, 114], [351, 117], [350, 135], [293, 132]], [[117, 113], [168, 116], [167, 135], [116, 132]], [[377, 99], [407, 99], [407, 115], [377, 115]], [[294, 99], [349, 99], [349, 114], [294, 114]], [[223, 99], [272, 99], [272, 114], [223, 114]], [[24, 99], [48, 99], [48, 115], [24, 115]], [[120, 98], [166, 98], [166, 114], [120, 114]], [[364, 80], [425, 80], [425, 95], [364, 95]], [[294, 81], [362, 81], [362, 93], [294, 93]], [[20, 80], [54, 80], [54, 95], [20, 95]], [[234, 79], [267, 79], [267, 94], [234, 94]], [[100, 76], [184, 78], [184, 96], [99, 94]], [[20, 62], [53, 62], [53, 77], [20, 77]], [[366, 62], [420, 59], [421, 75], [366, 77]], [[303, 60], [340, 60], [340, 75], [303, 75]], [[235, 60], [265, 60], [265, 76], [235, 76]], [[103, 60], [182, 60], [182, 75], [103, 75]], [[19, 43], [55, 43], [55, 58], [19, 58]], [[366, 43], [421, 40], [422, 55], [366, 58]], [[305, 42], [341, 42], [341, 57], [305, 57]], [[233, 42], [268, 42], [268, 57], [233, 57]], [[110, 42], [176, 42], [176, 56], [110, 56]], [[22, 24], [53, 24], [53, 40], [22, 40]], [[376, 23], [412, 23], [412, 38], [376, 38]], [[299, 23], [345, 23], [345, 38], [299, 38]], [[233, 23], [268, 23], [268, 39], [233, 39]], [[101, 21], [184, 21], [184, 40], [101, 40]], [[295, 3], [347, 3], [347, 20], [295, 20]], [[373, 1], [414, 1], [414, 20], [373, 20]], [[231, 1], [270, 1], [270, 20], [231, 20]], [[123, 1], [159, 1], [159, 21], [123, 21]], [[18, 1], [54, 1], [54, 21], [18, 21]]]\r\n",
      "\r\n",
      "[2021/12/25 14:56:01] root INFO: The predict time of ./doc/imgs/00018069.jpg: 0.6686491966247559\r\n",
      "[2021/12/25 14:56:01] root INFO: The visualized image saved in ./inference_results/det_res_00018069.jpg\r\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 402904 characters]",
      "text/plain": [
       "<Figure size 1440x576 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 参考代码\n",
    "# https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.4/tools/infer/predict_det.py\n",
    "# 预测\n",
    "!python tools/infer/predict_det.py --image_dir=\"./doc/imgs/00018069.jpg\" --det_model_dir=\"./inference/ch_PP-OCRv2_det_infer\" --use_gpu=False\n",
    "\n",
    "# 读取图像并显示出来，显示结果\n",
    "plt.figure(figsize=(20, 8))\n",
    "img_ori = cv2.imread(\"./doc/imgs/00018069.jpg\")\n",
    "img_out = cv2.imread(\"./inference_results/det_res_00018069.jpg\")\n",
    "plt.subplot(1, 2, 1)\n",
    "plt.imshow(img_ori[:,:,::-1])\n",
    "plt.subplot(1, 2, 2)\n",
    "plt.imshow(img_out[:,:,::-1])\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "那么具体是怎么实现的呢？下面给大家详细讲解下PP-OCRv2的推理模型加载与推理代码。\n",
    "\n",
    "首先需要定义参数设置如下所示。更多参数的介绍可以参考：[PaddleOCR推理过程参数介绍](https://github.com/PaddlePaddle/PaddleOCR/blob/release%2F2.4/doc/doc_ch/inference.md#%E5%85%AD%E5%8F%82%E6%95%B0%E8%A7%A3%E9%87%8A)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# 参考代码\n",
    "# https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.4/tools/infer/utility.py\n",
    "import argparse\n",
    "import os\n",
    "import sys\n",
    "import cv2\n",
    "import numpy as np\n",
    "import paddle\n",
    "from PIL import Image, ImageDraw, ImageFont\n",
    "import math\n",
    "from paddle import inference\n",
    "import time\n",
    "from ppocr.utils.logging import get_logger\n",
    "\n",
    "\n",
    "def str2bool(v):\n",
    "    return v.lower() in (\"true\", \"t\", \"1\")\n",
    "\n",
    "\n",
    "def init_args():\n",
    "    parser = argparse.ArgumentParser()\n",
    "    # params for prediction engine\n",
    "    parser.add_argument(\"--use_gpu\", type=str2bool, default=True)\n",
    "    parser.add_argument(\"--ir_optim\", type=str2bool, default=True)\n",
    "    parser.add_argument(\"--use_tensorrt\", type=str2bool, default=False)\n",
    "    parser.add_argument(\"--min_subgraph_size\", type=int, default=15)\n",
    "    parser.add_argument(\"--precision\", type=str, default=\"fp32\")\n",
    "    parser.add_argument(\"--gpu_mem\", type=int, default=500)\n",
    "\n",
    "    # params for text detector\n",
    "    parser.add_argument(\"--image_dir\", type=str)\n",
    "    parser.add_argument(\"--det_algorithm\", type=str, default='DB')\n",
    "    parser.add_argument(\"--det_model_dir\", type=str)\n",
    "    parser.add_argument(\"--det_limit_side_len\", type=float, default=960)\n",
    "    parser.add_argument(\"--det_limit_type\", type=str, default='max')\n",
    "\n",
    "    # DB parmas\n",
    "    parser.add_argument(\"--det_db_thresh\", type=float, default=0.3)\n",
    "    parser.add_argument(\"--det_db_box_thresh\", type=float, default=0.6)\n",
    "    parser.add_argument(\"--det_db_unclip_ratio\", type=float, default=1.5)\n",
    "    parser.add_argument(\"--max_batch_size\", type=int, default=10)\n",
    "    parser.add_argument(\"--use_dilation\", type=str2bool, default=False)\n",
    "    parser.add_argument(\"--det_db_score_mode\", type=str, default=\"fast\")\n",
    "    # EAST parmas\n",
    "    parser.add_argument(\"--det_east_score_thresh\", type=float, default=0.8)\n",
    "    parser.add_argument(\"--det_east_cover_thresh\", type=float, default=0.1)\n",
    "    parser.add_argument(\"--det_east_nms_thresh\", type=float, default=0.2)\n",
    "\n",
    "    # SAST parmas\n",
    "    parser.add_argument(\"--det_sast_score_thresh\", type=float, default=0.5)\n",
    "    parser.add_argument(\"--det_sast_nms_thresh\", type=float, default=0.2)\n",
    "    parser.add_argument(\"--det_sast_polygon\", type=str2bool, default=False)\n",
    "\n",
    "    # PSE parmas\n",
    "    parser.add_argument(\"--det_pse_thresh\", type=float, default=0)\n",
    "    parser.add_argument(\"--det_pse_box_thresh\", type=float, default=0.85)\n",
    "    parser.add_argument(\"--det_pse_min_area\", type=float, default=16)\n",
    "    parser.add_argument(\"--det_pse_box_type\", type=str, default='box')\n",
    "    parser.add_argument(\"--det_pse_scale\", type=int, default=1)\n",
    "\n",
    "    # params for text recognizer\n",
    "    parser.add_argument(\"--rec_algorithm\", type=str, default='CRNN')\n",
    "    parser.add_argument(\"--rec_model_dir\", type=str)\n",
    "    parser.add_argument(\"--rec_image_shape\", type=str, default=\"3, 32, 320\")\n",
    "    parser.add_argument(\"--rec_batch_num\", type=int, default=6)\n",
    "    parser.add_argument(\"--max_text_length\", type=int, default=25)\n",
    "    parser.add_argument(\n",
    "        \"--rec_char_dict_path\",\n",
    "        type=str,\n",
    "        default=\"./ppocr/utils/ppocr_keys_v1.txt\")\n",
    "    parser.add_argument(\"--use_space_char\", type=str2bool, default=True)\n",
    "    parser.add_argument(\n",
    "        \"--vis_font_path\", type=str, default=\"./doc/fonts/simfang.ttf\")\n",
    "    parser.add_argument(\"--drop_score\", type=float, default=0.5)\n",
    "\n",
    "    # params for e2e\n",
    "    parser.add_argument(\"--e2e_algorithm\", type=str, default='PGNet')\n",
    "    parser.add_argument(\"--e2e_model_dir\", type=str)\n",
    "    parser.add_argument(\"--e2e_limit_side_len\", type=float, default=768)\n",
    "    parser.add_argument(\"--e2e_limit_type\", type=str, default='max')\n",
    "\n",
    "    # PGNet parmas\n",
    "    parser.add_argument(\"--e2e_pgnet_score_thresh\", type=float, default=0.5)\n",
    "    parser.add_argument(\n",
    "        \"--e2e_char_dict_path\", type=str, default=\"./ppocr/utils/ic15_dict.txt\")\n",
    "    parser.add_argument(\"--e2e_pgnet_valid_set\", type=str, default='totaltext')\n",
    "    parser.add_argument(\"--e2e_pgnet_mode\", type=str, default='fast')\n",
    "\n",
    "    # params for text classifier\n",
    "    parser.add_argument(\"--use_angle_cls\", type=str2bool, default=False)\n",
    "    parser.add_argument(\"--cls_model_dir\", type=str)\n",
    "    parser.add_argument(\"--cls_image_shape\", type=str, default=\"3, 48, 192\")\n",
    "    parser.add_argument(\"--label_list\", type=list, default=['0', '180'])\n",
    "    parser.add_argument(\"--cls_batch_num\", type=int, default=6)\n",
    "    parser.add_argument(\"--cls_thresh\", type=float, default=0.9)\n",
    "\n",
    "    parser.add_argument(\"--enable_mkldnn\", type=str2bool, default=False)\n",
    "    parser.add_argument(\"--cpu_threads\", type=int, default=10)\n",
    "    parser.add_argument(\"--use_pdserving\", type=str2bool, default=False)\n",
    "    parser.add_argument(\"--warmup\", type=str2bool, default=False)\n",
    "\n",
    "    #\n",
    "    parser.add_argument(\n",
    "        \"--draw_img_save_dir\", type=str, default=\"./inference_results\")\n",
    "    parser.add_argument(\"--save_crop_res\", type=str2bool, default=False)\n",
    "    parser.add_argument(\"--crop_res_save_dir\", type=str, default=\"./output\")\n",
    "\n",
    "    # multi-process\n",
    "    parser.add_argument(\"--use_mp\", type=str2bool, default=False)\n",
    "    parser.add_argument(\"--total_process_num\", type=int, default=1)\n",
    "    parser.add_argument(\"--process_id\", type=int, default=0)\n",
    "\n",
    "    parser.add_argument(\"--benchmark\", type=str2bool, default=False)\n",
    "    parser.add_argument(\"--save_log_path\", type=str, default=\"./log_output/\")\n",
    "\n",
    "    parser.add_argument(\"--show_log\", type=str2bool, default=True)\n",
    "    parser.add_argument(\"--use_onnx\", type=str2bool, default=False)\n",
    "    # 这里需要注意，添加这个是因为直接在notebook中解析的话，sys.argv会在后面添加下面的内容，导致解析失败\n",
    "    # '-f', '/home/aistudio/.local/share/jupyter/runtime/kernel-e1221262-c656-4129-896f-1b197b6b782c.json'\n",
    "    parser.add_argument(\"-f\", type=str, default=None)\n",
    "    return parser\n",
    "\n",
    "\n",
    "def parse_args():\n",
    "    parser = init_args()\n",
    "    return parser.parse_args()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "下面和大家具体看下文字检测的具体代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2021/12/25 15:10:56] root INFO: 00018069.jpg\t[[[378, 249], [411, 252], [409, 266], [377, 265]], [[300, 250], [344, 250], [344, 265], [300, 265]], [[233, 250], [268, 250], [268, 265], [233, 265]], [[101, 249], [184, 249], [184, 266], [101, 266]], [[25, 250], [52, 250], [52, 266], [25, 266]], [[375, 233], [409, 233], [409, 247], [375, 247]], [[285, 233], [362, 233], [362, 247], [285, 247]], [[234, 233], [269, 233], [269, 247], [234, 247]], [[24, 234], [53, 234], [53, 247], [24, 247]], [[101, 230], [184, 230], [184, 248], [101, 248]], [[23, 214], [51, 214], [51, 229], [23, 229]], [[378, 213], [410, 213], [410, 228], [378, 228]], [[295, 211], [348, 214], [347, 229], [294, 226]], [[231, 213], [268, 213], [268, 228], [231, 228]], [[100, 212], [185, 212], [185, 229], [100, 229]], [[309, 195], [338, 195], [338, 209], [309, 209]], [[231, 194], [268, 194], [268, 209], [231, 209]], [[23, 194], [51, 194], [51, 210], [23, 210]], [[378, 193], [409, 193], [409, 209], [378, 209]], [[99, 193], [188, 193], [188, 208], [99, 208]], [[376, 175], [413, 175], [413, 190], [376, 190]], [[22, 175], [52, 175], [52, 192], [22, 192]], [[288, 173], [360, 173], [360, 191], [288, 191]], [[237, 174], [264, 174], [264, 190], [237, 190]], [[100, 173], [185, 173], [185, 191], [100, 191]], [[22, 156], [52, 156], [52, 172], [22, 172]], [[284, 154], [358, 154], [358, 172], [284, 172]], [[235, 155], [267, 155], [267, 171], [235, 171]], [[119, 155], [167, 155], [167, 170], [119, 170]], [[378, 138], [410, 135], [412, 152], [379, 155]], [[294, 136], [357, 136], [357, 153], [294, 153]], [[232, 137], [271, 137], [271, 152], [232, 152]], [[118, 137], [166, 137], [166, 151], [118, 151]], [[22, 137], [52, 137], [52, 152], [22, 152]], [[379, 119], [406, 119], [406, 135], [379, 135]], [[229, 118], [268, 118], [268, 134], [229, 134]], [[23, 118], [52, 118], [52, 134], [23, 134]], [[294, 114], [351, 117], [350, 135], [293, 132]], [[117, 113], [168, 116], [167, 135], [116, 132]], [[377, 99], [407, 99], [407, 115], [377, 115]], [[294, 99], [349, 99], [349, 114], [294, 114]], [[223, 99], [272, 99], [272, 114], [223, 114]], [[24, 99], [48, 99], [48, 115], [24, 115]], [[120, 98], [166, 98], [166, 114], [120, 114]], [[364, 80], [425, 80], [425, 95], [364, 95]], [[294, 81], [362, 81], [362, 93], [294, 93]], [[20, 80], [54, 80], [54, 95], [20, 95]], [[234, 79], [267, 79], [267, 94], [234, 94]], [[100, 76], [184, 78], [184, 96], [99, 94]], [[20, 62], [53, 62], [53, 77], [20, 77]], [[366, 62], [420, 59], [421, 75], [366, 77]], [[303, 60], [340, 60], [340, 75], [303, 75]], [[235, 60], [265, 60], [265, 76], [235, 76]], [[103, 60], [182, 60], [182, 75], [103, 75]], [[19, 43], [55, 43], [55, 58], [19, 58]], [[366, 43], [421, 40], [422, 55], [366, 58]], [[305, 42], [341, 42], [341, 57], [305, 57]], [[233, 42], [268, 42], [268, 57], [233, 57]], [[110, 42], [176, 42], [176, 56], [110, 56]], [[22, 24], [53, 24], [53, 40], [22, 40]], [[376, 23], [412, 23], [412, 38], [376, 38]], [[299, 23], [345, 23], [345, 38], [299, 38]], [[233, 23], [268, 23], [268, 39], [233, 39]], [[101, 21], [184, 21], [184, 40], [101, 40]], [[295, 3], [347, 3], [347, 20], [295, 20]], [[373, 1], [414, 1], [414, 20], [373, 20]], [[231, 1], [270, 1], [270, 20], [231, 20]], [[123, 1], [159, 1], [159, 21], [123, 21]], [[18, 1], [54, 1], [54, 21], [18, 21]]]\n",
      "\n",
      "[2021/12/25 15:10:56] root INFO: The predict time of ./doc/imgs/00018069.jpg: 0.04716134071350098\n",
      "[2021/12/25 15:10:56] root INFO: The visualized image saved in ./inference_results/det_res_00018069.jpg\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 126796 characters]",
      "text/plain": [
       "<Figure size 720x720 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 参考代码\n",
    "# https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.4/tools/infer/predict_det.py\n",
    "import os\n",
    "import sys\n",
    "import cv2\n",
    "import numpy as np\n",
    "import time\n",
    "\n",
    "import tools.infer.utility as utility\n",
    "from ppocr.utils.logging import get_logger\n",
    "from ppocr.utils.utility import get_image_file_list, check_and_read_gif\n",
    "from ppocr.data import create_operators, transform\n",
    "from ppocr.postprocess import build_post_process\n",
    "import json\n",
    "logger = get_logger()\n",
    "\n",
    "# 文字检测类\n",
    "class TextDetector(object):\n",
    "    def __init__(self, args):\n",
    "        self.args = args\n",
    "        self.det_algorithm = args.det_algorithm\n",
    "        pre_process_list = [{\n",
    "            'DetResizeForTest': {\n",
    "                'limit_side_len': args.det_limit_side_len,\n",
    "                'limit_type': args.det_limit_type,\n",
    "            }\n",
    "        }, {\n",
    "            'NormalizeImage': {\n",
    "                'std': [0.229, 0.224, 0.225],\n",
    "                'mean': [0.485, 0.456, 0.406],\n",
    "                'scale': '1./255.',\n",
    "                'order': 'hwc'\n",
    "            }\n",
    "        }, {\n",
    "            'ToCHWImage': None\n",
    "        }, {\n",
    "            'KeepKeys': {\n",
    "                'keep_keys': ['image', 'shape']\n",
    "            }\n",
    "        }]\n",
    "        postprocess_params = {}\n",
    "        if self.det_algorithm == \"DB\":\n",
    "            postprocess_params['name'] = 'DBPostProcess'\n",
    "            postprocess_params[\"thresh\"] = args.det_db_thresh\n",
    "            postprocess_params[\"box_thresh\"] = args.det_db_box_thresh\n",
    "            postprocess_params[\"max_candidates\"] = 1000\n",
    "            postprocess_params[\"unclip_ratio\"] = args.det_db_unclip_ratio\n",
    "            postprocess_params[\"use_dilation\"] = args.use_dilation\n",
    "            postprocess_params[\"score_mode\"] = args.det_db_score_mode\n",
    "        else:\n",
    "            logger.info(\"unknown det_algorithm:{}\".format(self.det_algorithm))\n",
    "            sys.exit(0)\n",
    "        # 初始化预测引擎\n",
    "        self.predictor, self.input_tensor, self.output_tensors, self.config = utility.create_predictor(\n",
    "            args, 'det', logger)\n",
    "        # 构建预处理算子\n",
    "        self.preprocess_op = create_operators(pre_process_list)\n",
    "        # 构建后处理算子\n",
    "        self.postprocess_op = build_post_process(postprocess_params)\n",
    "        \n",
    "\n",
    "    def order_points_clockwise(self, pts):\n",
    "        \"\"\"\n",
    "        参考: https://github.com/jrosebr1/imutils/blob/master/imutils/perspective.py\n",
    "        对检测出来的点进行按照顺时针排序\n",
    "        \"\"\"\n",
    "        xSorted = pts[np.argsort(pts[:, 0]), :]\n",
    "\n",
    "        leftMost = xSorted[:2, :]\n",
    "        rightMost = xSorted[2:, :]\n",
    "\n",
    "        leftMost = leftMost[np.argsort(leftMost[:, 1]), :]\n",
    "        (tl, bl) = leftMost\n",
    "\n",
    "        rightMost = rightMost[np.argsort(rightMost[:, 1]), :]\n",
    "        (tr, br) = rightMost\n",
    "\n",
    "        rect = np.array([tl, tr, br, bl], dtype=\"float32\")\n",
    "        return rect\n",
    "\n",
    "    def clip_det_res(self, points, img_height, img_width):\n",
    "        # 对检测结果根据宽高进行限幅，防止超出图像边界\n",
    "        for pno in range(points.shape[0]):\n",
    "            points[pno, 0] = int(min(max(points[pno, 0], 0), img_width - 1))\n",
    "            points[pno, 1] = int(min(max(points[pno, 1], 0), img_height - 1))\n",
    "        return points\n",
    "\n",
    "    def filter_tag_det_res(self, dt_boxes, image_shape):\n",
    "        # 去除小于特定尺寸的检测结果\n",
    "        img_height, img_width = image_shape[0:2]\n",
    "        dt_boxes_new = []\n",
    "        for box in dt_boxes:\n",
    "            box = self.order_points_clockwise(box)\n",
    "            box = self.clip_det_res(box, img_height, img_width)\n",
    "            rect_width = int(np.linalg.norm(box[0] - box[1]))\n",
    "            rect_height = int(np.linalg.norm(box[0] - box[3]))\n",
    "            if rect_width <= 3 or rect_height <= 3:\n",
    "                continue\n",
    "            dt_boxes_new.append(box)\n",
    "        dt_boxes = np.array(dt_boxes_new)\n",
    "        return dt_boxes\n",
    "\n",
    "    def filter_tag_det_res_only_clip(self, dt_boxes, image_shape):\n",
    "        # 仅对检测结果的边界进行限幅\n",
    "        img_height, img_width = image_shape[0:2]\n",
    "        dt_boxes_new = []\n",
    "        for box in dt_boxes:\n",
    "            box = self.clip_det_res(box, img_height, img_width)\n",
    "            dt_boxes_new.append(box)\n",
    "        dt_boxes = np.array(dt_boxes_new)\n",
    "        return dt_boxes\n",
    "\n",
    "    def __call__(self, img):\n",
    "        ori_im = img.copy()\n",
    "        data = {'image': img}\n",
    "\n",
    "        st = time.time()\n",
    "        \n",
    "        # 数据预处理\n",
    "        data = transform(data, self.preprocess_op)\n",
    "        img, shape_list = data\n",
    "        if img is None:\n",
    "            return None, 0\n",
    "        # 扩展bs维度：CHW -> NCHW\n",
    "        img = np.expand_dims(img, axis=0)\n",
    "        shape_list = np.expand_dims(shape_list, axis=0)\n",
    "        img = img.copy()\n",
    "        # 将数据拷贝到预测引擎中\n",
    "        self.input_tensor.copy_from_cpu(img)\n",
    "        # 自动推理\n",
    "        self.predictor.run()\n",
    "        outputs = []\n",
    "        # 将返回结果从预测引擎中拷贝回CPU\n",
    "        for output_tensor in self.output_tensors:\n",
    "            output = output_tensor.copy_to_cpu()\n",
    "            outputs.append(output)\n",
    "\n",
    "        preds = {}\n",
    "        if self.det_algorithm in ['DB', 'PSE']:\n",
    "            preds['maps'] = outputs[0]\n",
    "        else:\n",
    "            raise NotImplementedError\n",
    "\n",
    "        # 后处理\n",
    "        post_result = self.postprocess_op(preds, shape_list)\n",
    "        dt_boxes = post_result[0]['points']\n",
    "        dt_boxes = self.filter_tag_det_res(dt_boxes, ori_im.shape)\n",
    "        \n",
    "        et = time.time()\n",
    "        return dt_boxes, et - st\n",
    "\n",
    "# 设置参数\n",
    "args = parse_args()\n",
    "args.det_model_dir = \"./inference/ch_PP-OCRv2_det_infer\"\n",
    "args.image_dir = \"./doc/imgs/00018069.jpg\"\n",
    "\n",
    "# 获取图片列表\n",
    "image_file_list = get_image_file_list(args.image_dir)\n",
    "# 创建文本检测器对象\n",
    "text_detector = TextDetector(args)\n",
    "\n",
    "count = 0\n",
    "total_time = 0\n",
    "draw_img_save = \"./inference_results\"\n",
    "\n",
    "if not os.path.exists(draw_img_save):\n",
    "    os.makedirs(draw_img_save)\n",
    "save_results = []\n",
    "for image_file in image_file_list:\n",
    "    img = cv2.imread(image_file)\n",
    "    if img is None:\n",
    "        logger.info(\"error in loading image:{}\".format(image_file))\n",
    "        continue\n",
    "    st = time.time()\n",
    "    dt_boxes, _ = text_detector(img)\n",
    "    elapse = time.time() - st\n",
    "    if count > 0:\n",
    "        total_time += elapse\n",
    "    count += 1\n",
    "    save_pred = os.path.basename(image_file) + \"\\t\" + str(\n",
    "        json.dumps(np.array(dt_boxes).astype(np.int32).tolist())) + \"\\n\"\n",
    "    save_results.append(save_pred)\n",
    "    logger.info(save_pred)\n",
    "    logger.info(\"The predict time of {}: {}\".format(image_file, elapse))\n",
    "    src_im = utility.draw_text_det_res(dt_boxes, image_file)\n",
    "    img_name_pure = os.path.split(image_file)[-1]\n",
    "    img_path = os.path.join(draw_img_save,\n",
    "                            \"det_res_{}\".format(img_name_pure))\n",
    "    cv2.imwrite(img_path, src_im)\n",
    "    logger.info(\"The visualized image saved in {}\".format(img_path))\n",
    "    \n",
    "    break\n",
    "\n",
    "with open(os.path.join(draw_img_save, \"det_results.txt\"), 'w') as f:\n",
    "    f.writelines(save_results)\n",
    "    f.close()\n",
    "\n",
    "plt.figure(figsize=(10, 10))\n",
    "plt.imshow(src_im[:, :, ::-1])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "上面就完成了完整的文本检测流程。\n",
    "\n",
    "## 2.3 PP-OCRv2方向分类器模型推理\n",
    "\n",
    "同样地，对于方向分类器模型，我们也可以使用下面的命令快速体验其功能。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2021-12-25 15:40:13--  https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar\n",
      "Resolving paddleocr.bj.bcebos.com (paddleocr.bj.bcebos.com)... 100.67.200.6\n",
      "Connecting to paddleocr.bj.bcebos.com (paddleocr.bj.bcebos.com)|100.67.200.6|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 1454080 (1.4M) [application/x-tar]\n",
      "Saving to: ‘ch_ppocr_mobile_v2.0_cls_infer.tar’\n",
      "\n",
      "ch_ppocr_mobile_v2. 100%[===================>]   1.39M  --.-KB/s    in 0.04s   \n",
      "\n",
      "2021-12-25 15:40:13 (33.6 MB/s) - ‘ch_ppocr_mobile_v2.0_cls_infer.tar’ saved [1454080/1454080]\n",
      "\n",
      "[2021/12/25 15:40:15] root INFO: Predicts of ./doc/imgs_words/ch/word_1.jpg:['0', 0.9998784]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 62244 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 下载模型\n",
    "!cd inference && wget https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar -O ch_ppocr_mobile_v2.0_cls_infer.tar && tar -xf ch_ppocr_mobile_v2.0_cls_infer.tar\n",
    "# 预测\n",
    "!python tools/infer/predict_cls.py \\\n",
    "    --image_dir=\"./doc/imgs_words/ch/word_1.jpg\" \\\n",
    "    --cls_model_dir=\"./inference/ch_ppocr_mobile_v2.0_cls_infer\" \\\n",
    "    --use_gpu=False\n",
    "# 画图\n",
    "img = cv2.imread(\"./doc/imgs_words/ch/word_1.jpg\")\n",
    "plt.imshow(img[:,:,::-1])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "图片的方向是正向水平文本，预测结果正确。\n",
    "\n",
    "具体地，方向分类器的具体实现代码如下所示。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2021/12/25 15:43:28] root INFO: Predicts of ./doc/imgs_words/ch/word_4.jpg:['0', 0.9999982]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 31152 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 参考代码\n",
    "# https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.4/tools/infer/predict_cls.py\n",
    "import copy\n",
    "\n",
    "# 方向分类器实现的类\n",
    "class TextClassifier(object):\n",
    "    def __init__(self, args):\n",
    "        self.cls_image_shape = [int(v) for v in args.cls_image_shape.split(\",\")]\n",
    "        self.cls_batch_num = args.cls_batch_num\n",
    "        self.cls_thresh = args.cls_thresh\n",
    "        postprocess_params = {\n",
    "            'name': 'ClsPostProcess',\n",
    "            \"label_list\": args.label_list,\n",
    "        }\n",
    "        # 后处理算子\n",
    "        self.postprocess_op = build_post_process(postprocess_params)\n",
    "        # 初始化预测引擎\n",
    "        self.predictor, self.input_tensor, self.output_tensors, _ = \\\n",
    "            utility.create_predictor(args, 'cls', logger)\n",
    "\n",
    "    # 对图像进行resize并且normalize\n",
    "    def resize_norm_img(self, img):\n",
    "        imgC, imgH, imgW = self.cls_image_shape\n",
    "        h = img.shape[0]\n",
    "        w = img.shape[1]\n",
    "        ratio = w / float(h)\n",
    "        if math.ceil(imgH * ratio) > imgW:\n",
    "            resized_w = imgW\n",
    "        else:\n",
    "            resized_w = int(math.ceil(imgH * ratio))\n",
    "        resized_image = cv2.resize(img, (resized_w, imgH))\n",
    "        resized_image = resized_image.astype('float32')\n",
    "        if self.cls_image_shape[0] == 1:\n",
    "            resized_image = resized_image / 255\n",
    "            resized_image = resized_image[np.newaxis, :]\n",
    "        else:\n",
    "            resized_image = resized_image.transpose((2, 0, 1)) / 255\n",
    "        resized_image -= 0.5\n",
    "        resized_image /= 0.5\n",
    "        padding_im = np.zeros((imgC, imgH, imgW), dtype=np.float32)\n",
    "        padding_im[:, :, 0:resized_w] = resized_image\n",
    "        return padding_im\n",
    "\n",
    "    def __call__(self, img_list):\n",
    "        img_list = copy.deepcopy(img_list)\n",
    "        img_num = len(img_list)\n",
    "        # 记录宽高比\n",
    "        width_list = []\n",
    "        for img in img_list:\n",
    "            width_list.append(img.shape[1] / float(img.shape[0]))\n",
    "        # 排序，加速后续的预处理过程\n",
    "        indices = np.argsort(np.array(width_list))\n",
    "\n",
    "        cls_res = [['', 0.0]] * img_num\n",
    "        batch_num = self.cls_batch_num\n",
    "        elapse = 0\n",
    "        for beg_img_no in range(0, img_num, batch_num):\n",
    "            end_img_no = min(img_num, beg_img_no + batch_num)\n",
    "            norm_img_batch = []\n",
    "            max_wh_ratio = 0\n",
    "            starttime = time.time()\n",
    "            # 预处理数据，组batch\n",
    "            for ino in range(beg_img_no, end_img_no):\n",
    "                h, w = img_list[indices[ino]].shape[0:2]\n",
    "                wh_ratio = w * 1.0 / h\n",
    "                max_wh_ratio = max(max_wh_ratio, wh_ratio)\n",
    "            for ino in range(beg_img_no, end_img_no):\n",
    "                norm_img = self.resize_norm_img(img_list[indices[ino]])\n",
    "                norm_img = norm_img[np.newaxis, :]\n",
    "                norm_img_batch.append(norm_img)\n",
    "            norm_img_batch = np.concatenate(norm_img_batch)\n",
    "            norm_img_batch = norm_img_batch.copy()\n",
    "            # 将数据拷贝到预测引擎\n",
    "            self.input_tensor.copy_from_cpu(norm_img_batch)\n",
    "            # 自动推理过程\n",
    "            self.predictor.run()\n",
    "            # 将数据拷贝回CPU\n",
    "            prob_out = self.output_tensors[0].copy_to_cpu()\n",
    "            # 后处理\n",
    "            cls_result = self.postprocess_op(prob_out)\n",
    "            elapse += time.time() - starttime\n",
    "            for rno in range(len(cls_result)):\n",
    "                label, score = cls_result[rno]\n",
    "                cls_res[indices[beg_img_no + rno]] = [label, score]\n",
    "                if '180' in label and score > self.cls_thresh:\n",
    "                    img_list[indices[beg_img_no + rno]] = cv2.rotate(\n",
    "                        img_list[indices[beg_img_no + rno]], 1)\n",
    "        return img_list, cls_res, elapse\n",
    "\n",
    "args = parse_args()\n",
    "args.cls_model_dir = \"./inference/ch_ppocr_mobile_v2.0_cls_infer\"\n",
    "args.image_dir = \"./doc/imgs_words/ch/word_4.jpg\"\n",
    "\n",
    "image_file_list = get_image_file_list(args.image_dir)\n",
    "text_classifier = TextClassifier(args)\n",
    "valid_image_file_list = []\n",
    "img_list = []\n",
    "for image_file in image_file_list:\n",
    "    img = cv2.imread(image_file)\n",
    "    # 预测之前对图像旋转180度\n",
    "    # img = cv2.rotate(img, cv2.ROTATE_180)\n",
    "    if img is None:\n",
    "        logger.info(\"error in loading image:{}\".format(image_file))\n",
    "        continue\n",
    "    valid_image_file_list.append(image_file)\n",
    "    img_list.append(img)\n",
    "img_list, cls_res, predict_time = text_classifier(img_list)\n",
    "for ino in range(len(img_list)):\n",
    "    logger.info(\"Predicts of {}:{}\".format(valid_image_file_list[ino],\n",
    "                                            cls_res[ino]))\n",
    "\n",
    "plt.imshow(img[:,:,::-1])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "这里我们也可以将图像旋转180度之后，看下方向分类器的分类效果。\n",
    "\n",
    "上面就完成了完整的方向分类器的推理过程。\n",
    "\n",
    "\n",
    "## 2.4 PP-OCRv2文字识别模型推理\n",
    "\n",
    "对于文字识别模型，我们也可以使用下面的命令快速体验其功能。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2021-12-25 15:43:40--  https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar\n",
      "Resolving paddleocr.bj.bcebos.com (paddleocr.bj.bcebos.com)... 100.67.200.6\n",
      "Connecting to paddleocr.bj.bcebos.com (paddleocr.bj.bcebos.com)|100.67.200.6|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 8875520 (8.5M) [application/x-tar]\n",
      "Saving to: ‘ch_PP-OCRv2_rec_infer.tar’\n",
      "\n",
      "ch_PP-OCRv2_rec_inf 100%[===================>]   8.46M  --.-KB/s    in 0.1s    \n",
      "\n",
      "2021-12-25 15:43:40 (64.5 MB/s) - ‘ch_PP-OCRv2_rec_infer.tar’ saved [8875520/8875520]\n",
      "\n",
      "[2021/12/25 15:43:42] root INFO: Predicts of ./doc/imgs_words/ch/word_4.jpg:('实力活力', 0.9409585)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 31152 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 下载模型\n",
    "!cd inference && wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar -O ch_PP-OCRv2_rec_infer.tar &&  tar -xf ch_PP-OCRv2_rec_infer.tar\n",
    "# 预测\n",
    "!python tools/infer/predict_rec.py \\\n",
    "    --image_dir=\"./doc/imgs_words/ch/word_4.jpg\" \\\n",
    "    --rec_model_dir=\"./inference/ch_PP-OCRv2_rec_infer\" \\\n",
    "    --use_gpu=False\n",
    "\n",
    "# 读取图像并显示\n",
    "img = cv2.imread(\"./doc/imgs_words/ch/word_4.jpg\")\n",
    "plt.imshow(img[:,:,::-1])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "文字识别的具体代码如下所示。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2021/12/25 15:51:51] root INFO: Predicts of ./doc/imgs_words/ch/word_4.jpg:('实力活力', 0.9409561)\n"
     ]
    }
   ],
   "source": [
    "# 参考代码\n",
    "# https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.4/tools/infer/predict_rec.py\n",
    "class TextRecognizer(object):\n",
    "    def __init__(self, args):\n",
    "        self.rec_image_shape = [int(v) for v in args.rec_image_shape.split(\",\")]\n",
    "        self.rec_batch_num = args.rec_batch_num\n",
    "        self.rec_algorithm = args.rec_algorithm\n",
    "        postprocess_params = {\n",
    "            'name': 'CTCLabelDecode',\n",
    "            \"character_dict_path\": args.rec_char_dict_path,\n",
    "            \"use_space_char\": args.use_space_char\n",
    "        }\n",
    "        # 初始化预测引擎\n",
    "        self.predictor, self.input_tensor, self.output_tensors, self.config = \\\n",
    "            utility.create_predictor(args, 'rec', logger)\n",
    "        # 初始化后处理过程\n",
    "        self.postprocess_op = build_post_process(postprocess_params)\n",
    "\n",
    "    # 预处理核心逻辑\n",
    "    def resize_norm_img(self, img, max_wh_ratio):\n",
    "        imgC, imgH, imgW = self.rec_image_shape\n",
    "        assert imgC == img.shape[2]\n",
    "        imgW = int((32 * max_wh_ratio))\n",
    "        h, w = img.shape[:2]\n",
    "        ratio = w / float(h)\n",
    "        if math.ceil(imgH * ratio) > imgW:\n",
    "            resized_w = imgW\n",
    "        else:\n",
    "            resized_w = int(math.ceil(imgH * ratio))\n",
    "        resized_image = cv2.resize(img, (resized_w, imgH))\n",
    "        resized_image = resized_image.astype('float32')\n",
    "        # [0, 255] -> [0, 1]\n",
    "        resized_image = resized_image.transpose((2, 0, 1)) / 255\n",
    "        # [0, 1] -> [-0.5, 0.5]\n",
    "        resized_image -= 0.5\n",
    "        # [-0.5, 0.5] -> [-1, 1]\n",
    "        resized_image /= 0.5\n",
    "        padding_im = np.zeros((imgC, imgH, imgW), dtype=np.float32)\n",
    "        padding_im[:, :, 0:resized_w] = resized_image\n",
    "        return padding_im\n",
    "\n",
    "    # 对图像列表进行处理\n",
    "    def __call__(self, img_list):\n",
    "        img_num = len(img_list)\n",
    "        # 记录宽高比\n",
    "        width_list = []\n",
    "        for img in img_list:\n",
    "            width_list.append(img.shape[1] / float(img.shape[0]))\n",
    "        # 排序，加速处理过程\n",
    "        indices = np.argsort(np.array(width_list))\n",
    "        rec_res = [['', 0.0]] * img_num\n",
    "        batch_num = self.rec_batch_num\n",
    "        st = time.time()\n",
    "        for beg_img_no in range(0, img_num, batch_num):\n",
    "            end_img_no = min(img_num, beg_img_no + batch_num)\n",
    "            norm_img_batch = []\n",
    "            max_wh_ratio = 0\n",
    "            for ino in range(beg_img_no, end_img_no):\n",
    "                h, w = img_list[indices[ino]].shape[0:2]\n",
    "                wh_ratio = w * 1.0 / h\n",
    "                max_wh_ratio = max(max_wh_ratio, wh_ratio)\n",
    "            # 调用预处理方法并组batch\n",
    "            for ino in range(beg_img_no, end_img_no):\n",
    "                norm_img = self.resize_norm_img(img_list[indices[ino]],\n",
    "                                                max_wh_ratio)\n",
    "                norm_img = norm_img[np.newaxis, :]\n",
    "                norm_img_batch.append(norm_img)\n",
    "            norm_img_batch = np.concatenate(norm_img_batch)\n",
    "            norm_img_batch = norm_img_batch.copy()\n",
    "            \n",
    "            # 将数据拷贝到预测引擎中\n",
    "            self.input_tensor.copy_from_cpu(norm_img_batch)\n",
    "            # 自动化推理过程\n",
    "            self.predictor.run()\n",
    "            outputs = []\n",
    "            # 将数据拷贝到CPU\n",
    "            for output_tensor in self.output_tensors:\n",
    "                output = output_tensor.copy_to_cpu()\n",
    "                outputs.append(output)\n",
    "            if len(outputs) != 1:\n",
    "                preds = outputs\n",
    "            else:\n",
    "                preds = outputs[0]\n",
    "            # 后处理\n",
    "            rec_result = self.postprocess_op(preds)\n",
    "            for rno in range(len(rec_result)):\n",
    "                rec_res[indices[beg_img_no + rno]] = rec_result[rno]\n",
    "        return rec_res, time.time() - st\n",
    "\n",
    "\n",
    "# 定义参数\n",
    "args = parse_args()\n",
    "args.rec_model_dir = \"./inference/ch_PP-OCRv2_rec_infer\"\n",
    "args.image_dir = \"./doc/imgs_words/ch/word_4.jpg\"\n",
    "img_list = []\n",
    "\n",
    "image_file_list = get_image_file_list(args.image_dir)\n",
    "text_recognizer = TextRecognizer(args)\n",
    "valid_image_file_list = []\n",
    "for image_file in image_file_list:\n",
    "    img = cv2.imread(image_file)\n",
    "    if img is None:\n",
    "        logger.info(\"error in loading image:{}\".format(image_file))\n",
    "        continue\n",
    "    valid_image_file_list.append(image_file)\n",
    "    img_list.append(img)\n",
    "rec_res, _ = text_recognizer(img_list)\n",
    "for ino in range(len(img_list)):\n",
    "    logger.info(\"Predicts of {}:{}\".format(valid_image_file_list[ino],\n",
    "                                            rec_res[ino]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "## 2.5 PP-OCRv2 系统串联预测推理\n",
    "\n",
    "前面的内容给大家介绍了PP-OCRv2系统中，检测、方向分类器、识别模型的单独推理过程。为了方便大家端到端地使用，我们将这三个模块串联起来，组成了PP-OCRv2系统，并提供了相应的预测脚本。\n",
    "\n",
    "在执行PP-OCRv2的系统推理时，需要通过参数`image_dir`指定单张图像或者图像集合的路径、参数`det_model_dir`, `cls_model_dir` 和 `rec_model_dir` 分别指定检测、方向分类和识别的 `inference` 模型路径。参数 `use_angle_cls` 用于控制是否启用方向分类模型。`use_mp` 表示是否使用多进程。`total_process_num` 表示在使用多进程时的进程数。\n",
    "\n",
    "\n",
    "以图像文件`./doc/imgs/00018069.jpg`为例，预测的原始图像如下。\n",
    "\n",
    "<div align=\"center\">\n",
    "<img src=\"https://ai-studio-static-online.cdn.bcebos.com/5b00f13167014bb1b5b94af65c287509e645043507504ae99f912832e7998c5f\"  width = \"600\" />\n",
    "</div>\n",
    "<center>原始图像</center>\n",
    "\n",
    "\n",
    "如果串联预测时使用方向分类器，则可以使用下面的命令进行预测。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2021/12/25 15:53:46] root DEBUG: dt_boxes num : 69, elapse : 2.86064076423645\n",
      "[2021/12/25 15:53:46] root DEBUG: cls num  : 69, elapse : 0.05832171440124512\n",
      "[2021/12/25 15:53:46] root DEBUG: rec_res num  : 69, elapse : 0.11343073844909668\n",
      "[2021/12/25 15:53:46] root DEBUG: 0  Predict time of ./doc/imgs/00018069.jpg: 3.039s\n",
      "[2021/12/25 15:53:46] root DEBUG: 代号, 0.951\n",
      "[2021/12/25 15:53:46] root DEBUG: 项目, 0.981\n",
      "[2021/12/25 15:53:46] root DEBUG: 结果, 0.994\n",
      "[2021/12/25 15:53:46] root DEBUG: 参考值, 0.999\n",
      "[2021/12/25 15:53:46] root DEBUG: 单位, 0.994\n",
      "[2021/12/25 15:53:46] root DEBUG: 谷丙转氨酶, 0.982\n",
      "[2021/12/25 15:53:46] root DEBUG: 25.6, 0.936\n",
      "[2021/12/25 15:53:46] root DEBUG: 0--40, 0.993\n",
      "[2021/12/25 15:53:46] root DEBUG: ALT, 0.999\n",
      "[2021/12/25 15:53:46] root DEBUG: U/L, 0.961\n",
      "[2021/12/25 15:53:46] root DEBUG: 总胆红素, 0.970\n",
      "[2021/12/25 15:53:46] root DEBUG: 11.2, 0.980\n",
      "[2021/12/25 15:53:46] root DEBUG: TBIL, 0.987\n",
      "[2021/12/25 15:53:46] root DEBUG: <20, 0.976\n",
      "[2021/12/25 15:53:46] root DEBUG: UMOL/L, 0.754\n",
      "[2021/12/25 15:53:46] root DEBUG: 直接胆红素, 0.954\n",
      "[2021/12/25 15:53:46] root DEBUG: 3.3, 0.954\n",
      "[2021/12/25 15:53:46] root DEBUG: DBIL, 0.993\n",
      "[2021/12/25 15:53:46] root DEBUG: 01-7, 0.839\n",
      "[2021/12/25 15:53:46] root DEBUG: UMOL/L, 0.786\n",
      "[2021/12/25 15:53:46] root DEBUG: 间接胆红素, 0.961\n",
      "[2021/12/25 15:53:46] root DEBUG: IBIL, 0.996\n",
      "[2021/12/25 15:53:46] root DEBUG: 7.9, 0.868\n",
      "[2021/12/25 15:53:46] root DEBUG: 1.5--15, 0.887\n",
      "[2021/12/25 15:53:46] root DEBUG: UMOL/L, 0.864\n",
      "[2021/12/25 15:53:46] root DEBUG: TP, 0.927\n",
      "[2021/12/25 15:53:46] root DEBUG: 总蛋白, 0.983\n",
      "[2021/12/25 15:53:46] root DEBUG: +6 89, 0.801\n",
      "[2021/12/25 15:53:46] root DEBUG: 60--80, 0.996\n",
      "[2021/12/25 15:53:46] root DEBUG: 8/L, 0.991\n",
      "[2021/12/25 15:53:46] root DEBUG: 白蛋白, 0.984\n",
      "[2021/12/25 15:53:46] root DEBUG: ALB, 0.998\n",
      "[2021/12/25 15:53:46] root DEBUG: 35.1, 0.956\n",
      "[2021/12/25 15:53:46] root DEBUG: 33--55, 0.898\n",
      "[2021/12/25 15:53:46] root DEBUG: 8/L, 0.962\n",
      "[2021/12/25 15:53:46] root DEBUG: GLO, 0.985\n",
      "[2021/12/25 15:53:46] root DEBUG: 球蛋白, 0.981\n",
      "[2021/12/25 15:53:46] root DEBUG: 23.8, 0.962\n",
      "[2021/12/25 15:53:46] root DEBUG: 20--30, 0.986\n",
      "[2021/12/25 15:53:46] root DEBUG: 8/L, 0.821\n",
      "[2021/12/25 15:53:46] root DEBUG: 白球比, 0.992\n",
      "[2021/12/25 15:53:46] root DEBUG: 1.5, 0.993\n",
      "[2021/12/25 15:53:46] root DEBUG: A/G, 0.978\n",
      "[2021/12/25 15:53:46] root DEBUG: 11.5--2.5, 0.920\n",
      "[2021/12/25 15:53:46] root DEBUG: 碱性磷酸酶, 0.965\n",
      "[2021/12/25 15:53:46] root DEBUG: 93, 0.940\n",
      "[2021/12/25 15:53:46] root DEBUG: ALP, 0.998\n",
      "[2021/12/25 15:53:46] root DEBUG: 15--112, 0.964\n",
      "[2021/12/25 15:53:46] root DEBUG: IU/L, 0.895\n",
      "[2021/12/25 15:53:46] root DEBUG: 谷氨酰转肽酶, 0.902\n",
      "[2021/12/25 15:53:46] root DEBUG: GGT, 0.858\n",
      "[2021/12/25 15:53:46] root DEBUG: 14.3, 0.957\n",
      "[2021/12/25 15:53:46] root DEBUG: <50, 0.938\n",
      "[2021/12/25 15:53:46] root DEBUG: U/L, 0.928\n",
      "[2021/12/25 15:53:46] root DEBUG: 谷草转氨酶, 0.975\n",
      "[2021/12/25 15:53:46] root DEBUG: 16.3, 0.991\n",
      "[2021/12/25 15:53:46] root DEBUG: 8--40, 0.978\n",
      "[2021/12/25 15:53:46] root DEBUG: AST, 0.996\n",
      "[2021/12/25 15:53:46] root DEBUG: U/L, 0.872\n",
      "[2021/12/25 15:53:46] root DEBUG: 乳酸脱氢酶, 0.939\n",
      "[2021/12/25 15:53:46] root DEBUG: 167, 0.984\n",
      "[2021/12/25 15:53:46] root DEBUG: 114--240, 0.980\n",
      "[2021/12/25 15:53:46] root DEBUG: LDH, 0.990\n",
      "[2021/12/25 15:53:46] root DEBUG: U/L, 0.989\n",
      "[2021/12/25 15:53:46] root DEBUG: 腺甘脱氨酶, 0.975\n",
      "[2021/12/25 15:53:46] root DEBUG: ADA, 0.990\n",
      "[2021/12/25 15:53:46] root DEBUG: 12.6, 0.984\n",
      "[2021/12/25 15:53:46] root DEBUG: 4--24, 0.896\n",
      "[2021/12/25 15:53:46] root DEBUG: U/L, 0.877\n",
      "[2021/12/25 15:53:46] root DEBUG: The visualized image saved in ./inference_results/00018069.jpg\n",
      "[2021/12/25 15:53:46] root INFO: The predict total time is 3.074248790740967\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 467416 characters]",
      "text/plain": [
       "<Figure size 1440x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 使用方向分类器，运行PP-OCRv2系统\n",
    "!python tools/infer/predict_system.py \\\n",
    "    --image_dir=\"./doc/imgs/00018069.jpg\" \\\n",
    "    --det_model_dir=\"./inference/ch_PP-OCRv2_det_infer/\" \\\n",
    "    --cls_model_dir=\"./inference/ch_ppocr_mobile_v2.0_cls_infer/\" \\\n",
    "    --rec_model_dir=\"./inference/ch_PP-OCRv2_rec_infer/\" \\\n",
    "    --use_angle_cls=True\n",
    "\n",
    "# 可视化\n",
    "img = cv2.imread(\"./inference_results/00018069.jpg\")\n",
    "plt.figure(figsize=(20, 8))\n",
    "plt.imshow(img[..., ::-1])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "可视化识别结果默认保存到 `./inference_results` 文件夹里面。\n",
    "\n",
    "在图象中可视化出了检测框和识别结果，在上面的notebook中也打印出了具体的识别文件以及文件读取路径信息。\n",
    "  \n",
    "如果希望保存裁剪后的识别结果，可以将`save_crop_res`参数设置为True，最终结果保存在`output`目录下，其中部分裁剪后图像如下所示。保存的结果可以用于后续的识别模型标注与训练。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2021/12/22 00:23:26] root DEBUG: dt_boxes num : 69, elapse : 1.6756877899169922\n",
      "[2021/12/22 00:23:26] root DEBUG: cls num  : 69, elapse : 0.07216906547546387\n",
      "[2021/12/22 00:23:26] root DEBUG: rec_res num  : 69, elapse : 0.10237336158752441\n",
      "[2021/12/22 00:23:26] root DEBUG: 0, ('代号', 0.9509918)\n",
      "[2021/12/22 00:23:26] root DEBUG: 1, ('项目', 0.98095936)\n",
      "[2021/12/22 00:23:26] root DEBUG: 2, ('结果', 0.99443346)\n",
      "[2021/12/22 00:23:26] root DEBUG: 3, ('参考值', 0.99930096)\n",
      "[2021/12/22 00:23:26] root DEBUG: 4, ('单位', 0.99435925)\n",
      "[2021/12/22 00:23:26] root DEBUG: 5, ('谷丙转氨酶', 0.9817702)\n",
      "[2021/12/22 00:23:26] root DEBUG: 6, ('25.6', 0.9356477)\n",
      "[2021/12/22 00:23:26] root DEBUG: 7, ('0--40', 0.99340856)\n",
      "[2021/12/22 00:23:26] root DEBUG: 8, ('ALT', 0.9987676)\n",
      "[2021/12/22 00:23:26] root DEBUG: 9, ('U/L', 0.96127224)\n",
      "[2021/12/22 00:23:26] root DEBUG: 10, ('总胆红素', 0.9696524)\n",
      "[2021/12/22 00:23:26] root DEBUG: 11, ('11.2', 0.98009694)\n",
      "[2021/12/22 00:23:26] root DEBUG: 12, ('TBIL', 0.9866674)\n",
      "[2021/12/22 00:23:26] root DEBUG: 13, ('<20', 0.97562915)\n",
      "[2021/12/22 00:23:26] root DEBUG: 14, ('UMOL/L', 0.753596)\n",
      "[2021/12/22 00:23:26] root DEBUG: 15, ('直接胆红素', 0.95369786)\n",
      "[2021/12/22 00:23:26] root DEBUG: 16, ('3.3', 0.9539189)\n",
      "[2021/12/22 00:23:26] root DEBUG: 17, ('DBIL', 0.992847)\n",
      "[2021/12/22 00:23:26] root DEBUG: 18, ('01-7', 0.8393893)\n",
      "[2021/12/22 00:23:26] root DEBUG: 19, ('UMOL/L', 0.78601867)\n",
      "[2021/12/22 00:23:26] root DEBUG: 20, ('间接胆红素', 0.9609308)\n",
      "[2021/12/22 00:23:26] root DEBUG: 21, ('IBIL', 0.9956264)\n",
      "[2021/12/22 00:23:26] root DEBUG: 22, ('7.9', 0.8684632)\n",
      "[2021/12/22 00:23:26] root DEBUG: 23, ('1.5--15', 0.8868044)\n",
      "[2021/12/22 00:23:26] root DEBUG: 24, ('UMOL/L', 0.86376244)\n",
      "[2021/12/22 00:23:26] root DEBUG: 25, ('TP', 0.92697346)\n",
      "[2021/12/22 00:23:26] root DEBUG: 26, ('总蛋白', 0.9828675)\n",
      "[2021/12/22 00:23:26] root DEBUG: 27, ('+6 89', 0.8005167)\n",
      "[2021/12/22 00:23:26] root DEBUG: 28, ('60--80', 0.9963381)\n",
      "[2021/12/22 00:23:26] root DEBUG: 29, ('8/L', 0.9908847)\n",
      "[2021/12/22 00:23:26] root DEBUG: 30, ('白蛋白', 0.9840359)\n",
      "[2021/12/22 00:23:26] root DEBUG: 31, ('ALB', 0.997701)\n",
      "[2021/12/22 00:23:26] root DEBUG: 32, ('35.1', 0.9561434)\n",
      "[2021/12/22 00:23:26] root DEBUG: 33, ('33--55', 0.89755243)\n",
      "[2021/12/22 00:23:26] root DEBUG: 34, ('8/L', 0.96184856)\n",
      "[2021/12/22 00:23:26] root DEBUG: 35, ('GLO', 0.98490185)\n",
      "[2021/12/22 00:23:26] root DEBUG: 36, ('球蛋白', 0.9813283)\n",
      "[2021/12/22 00:23:26] root DEBUG: 37, ('23.8', 0.9624181)\n",
      "[2021/12/22 00:23:26] root DEBUG: 38, ('20--30', 0.98609096)\n",
      "[2021/12/22 00:23:26] root DEBUG: 39, ('8/L', 0.821223)\n",
      "[2021/12/22 00:23:26] root DEBUG: 40, ('白球比', 0.9924216)\n",
      "[2021/12/22 00:23:26] root DEBUG: 41, ('1.5', 0.9929995)\n",
      "[2021/12/22 00:23:26] root DEBUG: 42, ('A/G', 0.9776535)\n",
      "[2021/12/22 00:23:26] root DEBUG: 43, ('11.5--2.5', 0.92048424)\n",
      "[2021/12/22 00:23:26] root DEBUG: 44, ('碱性磷酸酶', 0.9653308)\n",
      "[2021/12/22 00:23:26] root DEBUG: 45, ('93', 0.9396907)\n",
      "[2021/12/22 00:23:26] root DEBUG: 46, ('ALP', 0.9981435)\n",
      "[2021/12/22 00:23:26] root DEBUG: 47, ('15--112', 0.96404344)\n",
      "[2021/12/22 00:23:26] root DEBUG: 48, ('IU/L', 0.89462817)\n",
      "[2021/12/22 00:23:26] root DEBUG: 49, ('谷氨酰转肽酶', 0.90209746)\n",
      "[2021/12/22 00:23:26] root DEBUG: 50, ('GGT', 0.85804963)\n",
      "[2021/12/22 00:23:26] root DEBUG: 51, ('14.3', 0.9572656)\n",
      "[2021/12/22 00:23:26] root DEBUG: 52, ('<50', 0.9381611)\n",
      "[2021/12/22 00:23:26] root DEBUG: 53, ('U/L', 0.9277277)\n",
      "[2021/12/22 00:23:26] root DEBUG: 54, ('谷草转氨酶', 0.9747366)\n",
      "[2021/12/22 00:23:26] root DEBUG: 55, ('16.3', 0.99106205)\n",
      "[2021/12/22 00:23:26] root DEBUG: 56, ('8--40', 0.9781853)\n",
      "[2021/12/22 00:23:26] root DEBUG: 57, ('AST', 0.99589247)\n",
      "[2021/12/22 00:23:26] root DEBUG: 58, ('U/L', 0.87197894)\n",
      "[2021/12/22 00:23:26] root DEBUG: 59, ('乳酸脱氢酶', 0.938639)\n",
      "[2021/12/22 00:23:26] root DEBUG: 60, ('167', 0.9842878)\n",
      "[2021/12/22 00:23:26] root DEBUG: 61, ('114--240', 0.980333)\n",
      "[2021/12/22 00:23:26] root DEBUG: 62, ('LDH', 0.99032784)\n",
      "[2021/12/22 00:23:26] root DEBUG: 63, ('U/L', 0.9886821)\n",
      "[2021/12/22 00:23:26] root DEBUG: 64, ('腺甘脱氨酶', 0.9749187)\n",
      "[2021/12/22 00:23:26] root DEBUG: 65, ('ADA', 0.99024695)\n",
      "[2021/12/22 00:23:26] root DEBUG: 66, ('12.6', 0.98363185)\n",
      "[2021/12/22 00:23:26] root DEBUG: 67, ('4--24', 0.8959759)\n",
      "[2021/12/22 00:23:26] root DEBUG: 68, ('U/L', 0.8774794)\n",
      "[2021/12/22 00:23:26] root DEBUG: 0  Predict time of ./doc/imgs/00018069.jpg: 1.868s\n",
      "[2021/12/22 00:23:26] root DEBUG: 代号, 0.951\n",
      "[2021/12/22 00:23:26] root DEBUG: 项目, 0.981\n",
      "[2021/12/22 00:23:26] root DEBUG: 结果, 0.994\n",
      "[2021/12/22 00:23:26] root DEBUG: 参考值, 0.999\n",
      "[2021/12/22 00:23:26] root DEBUG: 单位, 0.994\n",
      "[2021/12/22 00:23:26] root DEBUG: 谷丙转氨酶, 0.982\n",
      "[2021/12/22 00:23:26] root DEBUG: 25.6, 0.936\n",
      "[2021/12/22 00:23:26] root DEBUG: 0--40, 0.993\n",
      "[2021/12/22 00:23:26] root DEBUG: ALT, 0.999\n",
      "[2021/12/22 00:23:26] root DEBUG: U/L, 0.961\n",
      "[2021/12/22 00:23:26] root DEBUG: 总胆红素, 0.970\n",
      "[2021/12/22 00:23:26] root DEBUG: 11.2, 0.980\n",
      "[2021/12/22 00:23:26] root DEBUG: TBIL, 0.987\n",
      "[2021/12/22 00:23:26] root DEBUG: <20, 0.976\n",
      "[2021/12/22 00:23:26] root DEBUG: UMOL/L, 0.754\n",
      "[2021/12/22 00:23:26] root DEBUG: 直接胆红素, 0.954\n",
      "[2021/12/22 00:23:26] root DEBUG: 3.3, 0.954\n",
      "[2021/12/22 00:23:26] root DEBUG: DBIL, 0.993\n",
      "[2021/12/22 00:23:26] root DEBUG: 01-7, 0.839\n",
      "[2021/12/22 00:23:26] root DEBUG: UMOL/L, 0.786\n",
      "[2021/12/22 00:23:26] root DEBUG: 间接胆红素, 0.961\n",
      "[2021/12/22 00:23:26] root DEBUG: IBIL, 0.996\n",
      "[2021/12/22 00:23:26] root DEBUG: 7.9, 0.868\n",
      "[2021/12/22 00:23:26] root DEBUG: 1.5--15, 0.887\n",
      "[2021/12/22 00:23:26] root DEBUG: UMOL/L, 0.864\n",
      "[2021/12/22 00:23:26] root DEBUG: TP, 0.927\n",
      "[2021/12/22 00:23:26] root DEBUG: 总蛋白, 0.983\n",
      "[2021/12/22 00:23:26] root DEBUG: +6 89, 0.801\n",
      "[2021/12/22 00:23:26] root DEBUG: 60--80, 0.996\n",
      "[2021/12/22 00:23:26] root DEBUG: 8/L, 0.991\n",
      "[2021/12/22 00:23:26] root DEBUG: 白蛋白, 0.984\n",
      "[2021/12/22 00:23:26] root DEBUG: ALB, 0.998\n",
      "[2021/12/22 00:23:26] root DEBUG: 35.1, 0.956\n",
      "[2021/12/22 00:23:26] root DEBUG: 33--55, 0.898\n",
      "[2021/12/22 00:23:26] root DEBUG: 8/L, 0.962\n",
      "[2021/12/22 00:23:26] root DEBUG: GLO, 0.985\n",
      "[2021/12/22 00:23:26] root DEBUG: 球蛋白, 0.981\n",
      "[2021/12/22 00:23:26] root DEBUG: 23.8, 0.962\n",
      "[2021/12/22 00:23:26] root DEBUG: 20--30, 0.986\n",
      "[2021/12/22 00:23:26] root DEBUG: 8/L, 0.821\n",
      "[2021/12/22 00:23:26] root DEBUG: 白球比, 0.992\n",
      "[2021/12/22 00:23:26] root DEBUG: 1.5, 0.993\n",
      "[2021/12/22 00:23:26] root DEBUG: A/G, 0.978\n",
      "[2021/12/22 00:23:26] root DEBUG: 11.5--2.5, 0.920\n",
      "[2021/12/22 00:23:26] root DEBUG: 碱性磷酸酶, 0.965\n",
      "[2021/12/22 00:23:26] root DEBUG: 93, 0.940\n",
      "[2021/12/22 00:23:26] root DEBUG: ALP, 0.998\n",
      "[2021/12/22 00:23:26] root DEBUG: 15--112, 0.964\n",
      "[2021/12/22 00:23:26] root DEBUG: IU/L, 0.895\n",
      "[2021/12/22 00:23:26] root DEBUG: 谷氨酰转肽酶, 0.902\n",
      "[2021/12/22 00:23:26] root DEBUG: GGT, 0.858\n",
      "[2021/12/22 00:23:26] root DEBUG: 14.3, 0.957\n",
      "[2021/12/22 00:23:26] root DEBUG: <50, 0.938\n",
      "[2021/12/22 00:23:26] root DEBUG: U/L, 0.928\n",
      "[2021/12/22 00:23:26] root DEBUG: 谷草转氨酶, 0.975\n",
      "[2021/12/22 00:23:26] root DEBUG: 16.3, 0.991\n",
      "[2021/12/22 00:23:26] root DEBUG: 8--40, 0.978\n",
      "[2021/12/22 00:23:26] root DEBUG: AST, 0.996\n",
      "[2021/12/22 00:23:26] root DEBUG: U/L, 0.872\n",
      "[2021/12/22 00:23:26] root DEBUG: 乳酸脱氢酶, 0.939\n",
      "[2021/12/22 00:23:26] root DEBUG: 167, 0.984\n",
      "[2021/12/22 00:23:26] root DEBUG: 114--240, 0.980\n",
      "[2021/12/22 00:23:26] root DEBUG: LDH, 0.990\n",
      "[2021/12/22 00:23:26] root DEBUG: U/L, 0.989\n",
      "[2021/12/22 00:23:26] root DEBUG: 腺甘脱氨酶, 0.975\n",
      "[2021/12/22 00:23:26] root DEBUG: ADA, 0.990\n",
      "[2021/12/22 00:23:26] root DEBUG: 12.6, 0.984\n",
      "[2021/12/22 00:23:26] root DEBUG: 4--24, 0.896\n",
      "[2021/12/22 00:23:26] root DEBUG: U/L, 0.877\n",
      "[2021/12/22 00:23:26] root DEBUG: The visualized image saved in ./inference_results/00018069.jpg\n",
      "[2021/12/22 00:23:26] root INFO: The predict total time is 1.9217827320098877\n",
      "mg_crop_0.jpg\tmg_crop_22.jpg\tmg_crop_35.jpg\tmg_crop_48.jpg\tmg_crop_60.jpg\n",
      "mg_crop_10.jpg\tmg_crop_23.jpg\tmg_crop_36.jpg\tmg_crop_49.jpg\tmg_crop_61.jpg\n",
      "mg_crop_11.jpg\tmg_crop_24.jpg\tmg_crop_37.jpg\tmg_crop_4.jpg\tmg_crop_62.jpg\n",
      "mg_crop_12.jpg\tmg_crop_25.jpg\tmg_crop_38.jpg\tmg_crop_50.jpg\tmg_crop_63.jpg\n",
      "mg_crop_13.jpg\tmg_crop_26.jpg\tmg_crop_39.jpg\tmg_crop_51.jpg\tmg_crop_64.jpg\n",
      "mg_crop_14.jpg\tmg_crop_27.jpg\tmg_crop_3.jpg\tmg_crop_52.jpg\tmg_crop_65.jpg\n",
      "mg_crop_15.jpg\tmg_crop_28.jpg\tmg_crop_40.jpg\tmg_crop_53.jpg\tmg_crop_66.jpg\n",
      "mg_crop_16.jpg\tmg_crop_29.jpg\tmg_crop_41.jpg\tmg_crop_54.jpg\tmg_crop_67.jpg\n",
      "mg_crop_17.jpg\tmg_crop_2.jpg\tmg_crop_42.jpg\tmg_crop_55.jpg\tmg_crop_68.jpg\n",
      "mg_crop_18.jpg\tmg_crop_30.jpg\tmg_crop_43.jpg\tmg_crop_56.jpg\tmg_crop_6.jpg\n",
      "mg_crop_19.jpg\tmg_crop_31.jpg\tmg_crop_44.jpg\tmg_crop_57.jpg\tmg_crop_7.jpg\n",
      "mg_crop_1.jpg\tmg_crop_32.jpg\tmg_crop_45.jpg\tmg_crop_58.jpg\tmg_crop_8.jpg\n",
      "mg_crop_20.jpg\tmg_crop_33.jpg\tmg_crop_46.jpg\tmg_crop_59.jpg\tmg_crop_9.jpg\n",
      "mg_crop_21.jpg\tmg_crop_34.jpg\tmg_crop_47.jpg\tmg_crop_5.jpg\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 126636 characters]",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 13332 characters]",
      "text/plain": [
       "<Figure size 1008x288 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 裁剪文字检测的结果图像并保存\n",
    "!python tools/infer/predict_system.py \\\n",
    "    --image_dir=\"./doc/imgs/00018069.jpg\" \\\n",
    "    --det_model_dir=\"./inference/ch_PP-OCRv2_det_infer/\" \\\n",
    "    --cls_model_dir=\"./inference/ch_ppocr_mobile_v2.0_cls_infer/\" \\\n",
    "    --rec_model_dir=\"./inference/ch_PP-OCRv2_rec_infer/\" \\\n",
    "    --use_angle_cls=True \\\n",
    "    --save_crop_res=True\n",
    "\n",
    "!ls output\n",
    "\n",
    "plt.figure(figsize=(8, 8))\n",
    "plt.imshow(cv2.imread(\"./doc/imgs/00018069.jpg\")[:, :, ::-1])\n",
    "plt.show()\n",
    "plt.figure(figsize=(14, 4))\n",
    "plt.subplot(1,3,1)\n",
    "plt.imshow(cv2.imread(\"output/mg_crop_0.jpg\")[:, :, ::-1])\n",
    "plt.subplot(1,3,2)\n",
    "plt.imshow(cv2.imread(\"output/mg_crop_1.jpg\")[:, :, ::-1])\n",
    "plt.subplot(1,3,3)\n",
    "plt.imshow(cv2.imread(\"output/mg_crop_2.jpg\")[:, :, ::-1])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "串联预测通过`TextSystem`类进行实现，其具体实现过程与函数定义如下。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2021/12/22 00:23:29] root DEBUG: dt_boxes num : 69, elapse : 0.04321765899658203\n",
      "[2021/12/22 00:23:29] root DEBUG: cls num  : 69, elapse : 0.04562950134277344\n",
      "[2021/12/22 00:23:29] root DEBUG: rec_res num  : 69, elapse : 0.09602046012878418\n",
      "[2021/12/22 00:23:29] root DEBUG: 0  Predict time of ./doc/imgs/00018069.jpg: 0.195s\n",
      "[2021/12/22 00:23:29] root DEBUG: 代号, 0.951\n",
      "[2021/12/22 00:23:29] root DEBUG: 项目, 0.981\n",
      "[2021/12/22 00:23:29] root DEBUG: 结果, 0.994\n",
      "[2021/12/22 00:23:29] root DEBUG: 参考值, 0.999\n",
      "[2021/12/22 00:23:29] root DEBUG: 单位, 0.994\n",
      "[2021/12/22 00:23:29] root DEBUG: 谷丙转氨酶, 0.982\n",
      "[2021/12/22 00:23:29] root DEBUG: 25.6, 0.936\n",
      "[2021/12/22 00:23:29] root DEBUG: 0--40, 0.993\n",
      "[2021/12/22 00:23:29] root DEBUG: ALT, 0.999\n",
      "[2021/12/22 00:23:29] root DEBUG: U/L, 0.961\n",
      "[2021/12/22 00:23:29] root DEBUG: 总胆红素, 0.970\n",
      "[2021/12/22 00:23:29] root DEBUG: 11.2, 0.980\n",
      "[2021/12/22 00:23:29] root DEBUG: TBIL, 0.987\n",
      "[2021/12/22 00:23:29] root DEBUG: <20, 0.976\n",
      "[2021/12/22 00:23:29] root DEBUG: UMOL/L, 0.754\n",
      "[2021/12/22 00:23:29] root DEBUG: 直接胆红素, 0.954\n",
      "[2021/12/22 00:23:29] root DEBUG: 3.3, 0.954\n",
      "[2021/12/22 00:23:29] root DEBUG: DBIL, 0.993\n",
      "[2021/12/22 00:23:29] root DEBUG: 01-7, 0.839\n",
      "[2021/12/22 00:23:29] root DEBUG: UMOL/L, 0.786\n",
      "[2021/12/22 00:23:29] root DEBUG: 间接胆红素, 0.961\n",
      "[2021/12/22 00:23:29] root DEBUG: IBIL, 0.996\n",
      "[2021/12/22 00:23:29] root DEBUG: 7.9, 0.868\n",
      "[2021/12/22 00:23:29] root DEBUG: 1.5--15, 0.887\n",
      "[2021/12/22 00:23:29] root DEBUG: UMOL/L, 0.864\n",
      "[2021/12/22 00:23:29] root DEBUG: TP, 0.927\n",
      "[2021/12/22 00:23:29] root DEBUG: 总蛋白, 0.983\n",
      "[2021/12/22 00:23:29] root DEBUG: +6 89, 0.801\n",
      "[2021/12/22 00:23:29] root DEBUG: 60--80, 0.996\n",
      "[2021/12/22 00:23:29] root DEBUG: 8/L, 0.991\n",
      "[2021/12/22 00:23:29] root DEBUG: 白蛋白, 0.984\n",
      "[2021/12/22 00:23:29] root DEBUG: ALB, 0.998\n",
      "[2021/12/22 00:23:29] root DEBUG: 35.1, 0.956\n",
      "[2021/12/22 00:23:29] root DEBUG: 33--55, 0.898\n",
      "[2021/12/22 00:23:29] root DEBUG: 8/L, 0.962\n",
      "[2021/12/22 00:23:29] root DEBUG: GLO, 0.985\n",
      "[2021/12/22 00:23:29] root DEBUG: 球蛋白, 0.981\n",
      "[2021/12/22 00:23:29] root DEBUG: 23.8, 0.962\n",
      "[2021/12/22 00:23:29] root DEBUG: 20--30, 0.986\n",
      "[2021/12/22 00:23:29] root DEBUG: 8/L, 0.821\n",
      "[2021/12/22 00:23:29] root DEBUG: 白球比, 0.992\n",
      "[2021/12/22 00:23:29] root DEBUG: 1.5, 0.993\n",
      "[2021/12/22 00:23:29] root DEBUG: A/G, 0.978\n",
      "[2021/12/22 00:23:29] root DEBUG: 11.5--2.5, 0.920\n",
      "[2021/12/22 00:23:29] root DEBUG: 碱性磷酸酶, 0.965\n",
      "[2021/12/22 00:23:29] root DEBUG: 93, 0.940\n",
      "[2021/12/22 00:23:29] root DEBUG: ALP, 0.998\n",
      "[2021/12/22 00:23:29] root DEBUG: 15--112, 0.964\n",
      "[2021/12/22 00:23:29] root DEBUG: IU/L, 0.895\n",
      "[2021/12/22 00:23:29] root DEBUG: 谷氨酰转肽酶, 0.902\n",
      "[2021/12/22 00:23:29] root DEBUG: GGT, 0.858\n",
      "[2021/12/22 00:23:29] root DEBUG: 14.3, 0.957\n",
      "[2021/12/22 00:23:29] root DEBUG: <50, 0.938\n",
      "[2021/12/22 00:23:29] root DEBUG: U/L, 0.928\n",
      "[2021/12/22 00:23:29] root DEBUG: 谷草转氨酶, 0.975\n",
      "[2021/12/22 00:23:29] root DEBUG: 16.3, 0.991\n",
      "[2021/12/22 00:23:29] root DEBUG: 8--40, 0.978\n",
      "[2021/12/22 00:23:29] root DEBUG: AST, 0.996\n",
      "[2021/12/22 00:23:29] root DEBUG: U/L, 0.872\n",
      "[2021/12/22 00:23:29] root DEBUG: 乳酸脱氢酶, 0.939\n",
      "[2021/12/22 00:23:29] root DEBUG: 167, 0.984\n",
      "[2021/12/22 00:23:29] root DEBUG: 114--240, 0.980\n",
      "[2021/12/22 00:23:29] root DEBUG: LDH, 0.990\n",
      "[2021/12/22 00:23:29] root DEBUG: U/L, 0.989\n",
      "[2021/12/22 00:23:29] root DEBUG: 腺甘脱氨酶, 0.975\n",
      "[2021/12/22 00:23:29] root DEBUG: ADA, 0.990\n",
      "[2021/12/22 00:23:29] root DEBUG: 12.6, 0.984\n",
      "[2021/12/22 00:23:29] root DEBUG: 4--24, 0.896\n",
      "[2021/12/22 00:23:29] root DEBUG: U/L, 0.877\n",
      "[2021/12/22 00:23:29] root DEBUG: The visualized image saved in ./inference_results/00018069.jpg\n",
      "[2021/12/22 00:23:29] root INFO: The predict total time is 0.28207850456237793\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 126636 characters]",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 227904 characters]",
      "text/plain": [
       "<Figure size 1152x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 参考代码：https://github.com/PaddlePaddle/PaddleOCR/blob/release%2F2.4/tools/infer/predict_system.py\n",
    "from tools.infer.utility import draw_ocr_box_txt, get_rotate_crop_image\n",
    "from ppocr.utils.utility import get_image_file_list\n",
    "\n",
    "class TextSystem(object):\n",
    "    # 初始化函数\n",
    "    def __init__(self, args):\n",
    "        self.args = args\n",
    "  \t\t# 如果不希望显示log，可以将show_log设置为False\n",
    "        if not args.show_log:\n",
    "            logger.setLevel(logging.INFO)\n",
    "        # 定义文本检测模型预测引擎\n",
    "        self.text_detector = TextDetector(args)\n",
    "        # 定义文本识别模型预测引擎\n",
    "        self.text_recognizer = TextRecognizer(args)\n",
    "        # 是否使用方向分类器\n",
    "        self.use_angle_cls = args.use_angle_cls\n",
    "        # 得分阈值，根据该阈值判断检测与识别结果是否需要进行可视化或者返回\n",
    "        self.drop_score = args.drop_score\n",
    "        # 定义方向分类器预测引擎\n",
    "        if self.use_angle_cls:\n",
    "            self.text_classifier = TextClassifier(args)\n",
    "\t\n",
    "  \t# 保存文本检测结果图像\n",
    "    def draw_crop_rec_res(self, output_dir, img_crop_list, rec_res):\n",
    "        os.makedirs(output_dir, exist_ok=True)\n",
    "        bbox_num = len(img_crop_list)\n",
    "        for bno in range(bbox_num):\n",
    "            cv2.imwrite(\n",
    "                os.path.join(output_dir,\n",
    "                             f\"mg_crop_{bno+self.crop_image_res_index}.jpg\"),\n",
    "                img_crop_list[bno])\n",
    "            logger.debug(f\"{bno}, {rec_res[bno]}\")\n",
    "        self.crop_image_res_index += bbox_num\n",
    "\t\n",
    "    # 核心预测函数\n",
    "    def __call__(self, img, cls=True):\n",
    "        ori_im = img.copy()\n",
    "        # 获取检测文本检测结果\n",
    "        dt_boxes, elapse = self.text_detector(img)\n",
    "        logger.debug(\"dt_boxes num : {}, elapse : {}\".format(\n",
    "            len(dt_boxes), elapse))\n",
    "        if dt_boxes is None:\n",
    "            return None, None\n",
    "        img_crop_list = []\n",
    "        # 对检测框进行排序，顺序为：优先从上到下，其次从左到右\n",
    "        dt_boxes = sorted_boxes(dt_boxes)\n",
    "        # 对检测结果进行透视变换与校正\n",
    "        for bno in range(len(dt_boxes)):\n",
    "            tmp_box = copy.deepcopy(dt_boxes[bno])\n",
    "            img_crop = get_rotate_crop_image(ori_im, tmp_box)\n",
    "            img_crop_list.append(img_crop)\n",
    "        # 使用方向分类器对检测结果进行转正\n",
    "        if self.use_angle_cls and cls:\n",
    "            img_crop_list, angle_list, elapse = self.text_classifier(\n",
    "                img_crop_list)\n",
    "            logger.debug(\"cls num  : {}, elapse : {}\".format(\n",
    "                len(img_crop_list), elapse))\n",
    "        # 获取文本识别结果\n",
    "        rec_res, elapse = self.text_recognizer(img_crop_list)\n",
    "        logger.debug(\"rec_res num  : {}, elapse : {}\".format(\n",
    "            len(rec_res), elapse))\n",
    "        # 保存经过校正之后的文本检测图像\n",
    "        if self.args.save_crop_res:\n",
    "            self.draw_crop_rec_res(self.args.crop_res_save_dir, img_crop_list,\n",
    "                                   rec_res)\n",
    "        filter_boxes, filter_rec_res = [], []\n",
    "        # 根据识别得分的阈值对结果进行过滤，如果得分小于阈值，就过滤掉\n",
    "        for box, rec_result in zip(dt_boxes, rec_res):\n",
    "            text, score = rec_result\n",
    "            if score >= self.drop_score:\n",
    "                filter_boxes.append(box)\n",
    "                filter_rec_res.append(rec_result)\n",
    "        return filter_boxes, filter_rec_res\n",
    "\n",
    "def sorted_boxes(dt_boxes):\n",
    "    # 对检测框进行排序：优先从上到下，其次从左到右\n",
    "    num_boxes = dt_boxes.shape[0]\n",
    "    sorted_boxes = sorted(dt_boxes, key=lambda x: (x[0][1], x[0][0]))\n",
    "    _boxes = list(sorted_boxes)\n",
    "\n",
    "    for i in range(num_boxes - 1):\n",
    "        if abs(_boxes[i + 1][0][1] - _boxes[i][0][1]) < 10 and \\\n",
    "                (_boxes[i + 1][0][0] < _boxes[i][0][0]):\n",
    "            tmp = _boxes[i]\n",
    "            _boxes[i] = _boxes[i + 1]\n",
    "            _boxes[i + 1] = tmp\n",
    "    return _boxes\n",
    "\n",
    "args = parse_args()\n",
    "args.cls_model_dir = \"./inference/ch_ppocr_mobile_v2.0_cls_infer\"\n",
    "args.det_model_dir=\"./inference/ch_PP-OCRv2_det_infer/\"\n",
    "args.rec_model_dir=\"./inference/ch_PP-OCRv2_rec_infer/\"\n",
    "args.image_dir = \"./doc/imgs/00018069.jpg\"\n",
    "args.use_angle_cls=True\n",
    "args.use_gpu=True\n",
    "\n",
    "image_file_list = get_image_file_list(args.image_dir)\n",
    "image_file_list = image_file_list[args.process_id::args.total_process_num]\n",
    "text_sys = TextSystem(args)\n",
    "is_visualize = True\n",
    "font_path = args.vis_font_path\n",
    "drop_score = args.drop_score\n",
    "\n",
    "total_time = 0\n",
    "cpu_mem, gpu_mem, gpu_util = 0, 0, 0\n",
    "_st = time.time()\n",
    "count = 0\n",
    "for idx, image_file in enumerate(image_file_list):\n",
    "    img = cv2.imread(image_file)\n",
    "    if img is None:\n",
    "        logger.debug(\"error in loading image:{}\".format(image_file))\n",
    "        continue\n",
    "    starttime = time.time()\n",
    "    dt_boxes, rec_res = text_sys(img)\n",
    "    elapse = time.time() - starttime\n",
    "    total_time += elapse\n",
    "\n",
    "    logger.debug(\n",
    "        str(idx) + \"  Predict time of %s: %.3fs\" % (image_file, elapse))\n",
    "    for text, score in rec_res:\n",
    "        logger.debug(\"{}, {:.3f}\".format(text, score))\n",
    "\n",
    "    if is_visualize:\n",
    "        image = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n",
    "        boxes = dt_boxes\n",
    "        txts = [rec_res[i][0] for i in range(len(rec_res))]\n",
    "        scores = [rec_res[i][1] for i in range(len(rec_res))]\n",
    "\n",
    "        draw_img = draw_ocr_box_txt(\n",
    "            image,\n",
    "            boxes,\n",
    "            txts,\n",
    "            scores,\n",
    "            drop_score=drop_score,\n",
    "            font_path=font_path)\n",
    "        draw_img_save_dir = args.draw_img_save_dir\n",
    "        os.makedirs(draw_img_save_dir, exist_ok=True)\n",
    "        cv2.imwrite(\n",
    "            os.path.join(draw_img_save_dir, os.path.basename(image_file)),\n",
    "            draw_img[:, :, ::-1])\n",
    "        logger.debug(\"The visualized image saved in {}\".format(\n",
    "            os.path.join(draw_img_save_dir, os.path.basename(image_file))))\n",
    "\n",
    "logger.info(\"The predict total time is {}\".format(time.time() - _st))\n",
    "\n",
    "plt.figure(figsize=(8, 8))\n",
    "plt.imshow(image)\n",
    "plt.show()\n",
    "plt.figure(figsize=(16, 8))\n",
    "plt.imshow(draw_img)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "\n",
    "## 2.6 PP-OCRv2 使用whl包预测推理\n",
    "\n",
    "为了更加方便快速体验OCR文本检测与识别模型，PaddleOCR提供了基于Paddle Inference预测引擎的whl包，方便您一键安装，体验PaddleOCR。\n",
    "\n",
    "### 2.6.1 安装whl包\n",
    "\n",
    "使用pip安装paddleocr的whl包，命令如下。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple\n",
      "Collecting paddleocr==2.3.0.2\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/e1/b6/5486e674ce096667dff247b58bf0fb789c2ce17a10e546c2686a2bb07aec/paddleocr-2.3.0.2-py3-none-any.whl (250 kB)\n",
      "     |████████████████████████████████| 250 kB 13.6 MB/s            \n",
      "\u001b[?25hRequirement already satisfied: imgaug==0.4.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (0.4.0)\n",
      "Requirement already satisfied: opencv-contrib-python==4.4.0.46 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (4.4.0.46)\n",
      "Requirement already satisfied: python-Levenshtein in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (0.12.2)\n",
      "Requirement already satisfied: pyclipper in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (1.3.0.post2)\n",
      "Requirement already satisfied: numpy in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (1.20.3)\n",
      "Requirement already satisfied: visualdl in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (2.2.0)\n",
      "Requirement already satisfied: lmdb in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (1.2.1)\n",
      "Requirement already satisfied: scikit-image in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (0.19.1)\n",
      "Requirement already satisfied: shapely in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (1.8.0)\n",
      "Requirement already satisfied: cython in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (0.29)\n",
      "Requirement already satisfied: openpyxl in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (3.0.5)\n",
      "Requirement already satisfied: lxml in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (4.7.1)\n",
      "Requirement already satisfied: premailer in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (3.10.0)\n",
      "Requirement already satisfied: tqdm in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (4.27.0)\n",
      "Requirement already satisfied: fasttext==0.9.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddleocr==2.3.0.2) (0.9.1)\n",
      "Requirement already satisfied: setuptools>=0.7.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from fasttext==0.9.1->paddleocr==2.3.0.2) (56.2.0)\n",
      "Requirement already satisfied: pybind11>=2.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from fasttext==0.9.1->paddleocr==2.3.0.2) (2.8.1)\n",
      "Requirement already satisfied: scipy in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from imgaug==0.4.0->paddleocr==2.3.0.2) (1.6.3)\n",
      "Requirement already satisfied: Pillow in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from imgaug==0.4.0->paddleocr==2.3.0.2) (7.1.2)\n",
      "Requirement already satisfied: imageio in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from imgaug==0.4.0->paddleocr==2.3.0.2) (2.6.1)\n",
      "Requirement already satisfied: matplotlib in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from imgaug==0.4.0->paddleocr==2.3.0.2) (2.2.3)\n",
      "Requirement already satisfied: six in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from imgaug==0.4.0->paddleocr==2.3.0.2) (1.15.0)\n",
      "Requirement already satisfied: opencv-python in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from imgaug==0.4.0->paddleocr==2.3.0.2) (4.1.1.26)\n",
      "Requirement already satisfied: tifffile>=2019.7.26 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from scikit-image->paddleocr==2.3.0.2) (2021.11.2)\n",
      "Requirement already satisfied: networkx>=2.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from scikit-image->paddleocr==2.3.0.2) (2.4)\n",
      "Requirement already satisfied: PyWavelets>=1.1.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from scikit-image->paddleocr==2.3.0.2) (1.2.0)\n",
      "Requirement already satisfied: packaging>=20.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from scikit-image->paddleocr==2.3.0.2) (20.9)\n",
      "Requirement already satisfied: et-xmlfile in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from openpyxl->paddleocr==2.3.0.2) (1.0.1)\n",
      "Requirement already satisfied: jdcal in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from openpyxl->paddleocr==2.3.0.2) (1.4.1)\n",
      "Requirement already satisfied: cssutils in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from premailer->paddleocr==2.3.0.2) (2.3.0)\n",
      "Requirement already satisfied: requests in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from premailer->paddleocr==2.3.0.2) (2.22.0)\n",
      "Requirement already satisfied: cssselect in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from premailer->paddleocr==2.3.0.2) (1.1.0)\n",
      "Requirement already satisfied: cachetools in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from premailer->paddleocr==2.3.0.2) (4.0.0)\n",
      "Requirement already satisfied: pre-commit in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->paddleocr==2.3.0.2) (1.21.0)\n",
      "Requirement already satisfied: bce-python-sdk in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->paddleocr==2.3.0.2) (0.8.53)\n",
      "Requirement already satisfied: shellcheck-py in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->paddleocr==2.3.0.2) (0.7.1.1)\n",
      "Requirement already satisfied: pandas in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->paddleocr==2.3.0.2) (1.1.5)\n",
      "Requirement already satisfied: flask>=1.1.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->paddleocr==2.3.0.2) (1.1.1)\n",
      "Requirement already satisfied: flake8>=3.7.9 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->paddleocr==2.3.0.2) (3.8.2)\n",
      "Requirement already satisfied: protobuf>=3.11.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->paddleocr==2.3.0.2) (3.14.0)\n",
      "Requirement already satisfied: Flask-Babel>=1.0.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from visualdl->paddleocr==2.3.0.2) (1.0.0)\n",
      "Requirement already satisfied: importlib-metadata in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flake8>=3.7.9->visualdl->paddleocr==2.3.0.2) (0.23)\n",
      "Requirement already satisfied: mccabe<0.7.0,>=0.6.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flake8>=3.7.9->visualdl->paddleocr==2.3.0.2) (0.6.1)\n",
      "Requirement already satisfied: pyflakes<2.3.0,>=2.2.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flake8>=3.7.9->visualdl->paddleocr==2.3.0.2) (2.2.0)\n",
      "Requirement already satisfied: pycodestyle<2.7.0,>=2.6.0a1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flake8>=3.7.9->visualdl->paddleocr==2.3.0.2) (2.6.0)\n",
      "Requirement already satisfied: click>=5.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flask>=1.1.1->visualdl->paddleocr==2.3.0.2) (7.0)\n",
      "Requirement already satisfied: Jinja2>=2.10.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flask>=1.1.1->visualdl->paddleocr==2.3.0.2) (2.11.0)\n",
      "Requirement already satisfied: Werkzeug>=0.15 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flask>=1.1.1->visualdl->paddleocr==2.3.0.2) (0.16.0)\n",
      "Requirement already satisfied: itsdangerous>=0.24 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from flask>=1.1.1->visualdl->paddleocr==2.3.0.2) (1.1.0)\n",
      "Requirement already satisfied: pytz in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from Flask-Babel>=1.0.0->visualdl->paddleocr==2.3.0.2) (2019.3)\n",
      "Requirement already satisfied: Babel>=2.3 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from Flask-Babel>=1.0.0->visualdl->paddleocr==2.3.0.2) (2.8.0)\n",
      "Requirement already satisfied: decorator>=4.3.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from networkx>=2.2->scikit-image->paddleocr==2.3.0.2) (4.4.2)\n",
      "Requirement already satisfied: pyparsing>=2.0.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from packaging>=20.0->scikit-image->paddleocr==2.3.0.2) (2.4.2)\n",
      "Requirement already satisfied: future>=0.6.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from bce-python-sdk->visualdl->paddleocr==2.3.0.2) (0.18.0)\n",
      "Requirement already satisfied: pycryptodome>=3.8.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from bce-python-sdk->visualdl->paddleocr==2.3.0.2) (3.9.9)\n",
      "Requirement already satisfied: python-dateutil>=2.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from matplotlib->imgaug==0.4.0->paddleocr==2.3.0.2) (2.8.0)\n",
      "Requirement already satisfied: cycler>=0.10 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from matplotlib->imgaug==0.4.0->paddleocr==2.3.0.2) (0.10.0)\n",
      "Requirement already satisfied: kiwisolver>=1.0.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from matplotlib->imgaug==0.4.0->paddleocr==2.3.0.2) (1.1.0)\n",
      "Requirement already satisfied: cfgv>=2.0.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->paddleocr==2.3.0.2) (2.0.1)\n",
      "Requirement already satisfied: toml in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->paddleocr==2.3.0.2) (0.10.0)\n",
      "Requirement already satisfied: nodeenv>=0.11.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->paddleocr==2.3.0.2) (1.3.4)\n",
      "Requirement already satisfied: aspy.yaml in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->paddleocr==2.3.0.2) (1.3.0)\n",
      "Requirement already satisfied: virtualenv>=15.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->paddleocr==2.3.0.2) (16.7.9)\n",
      "Requirement already satisfied: identify>=1.0.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->paddleocr==2.3.0.2) (1.4.10)\n",
      "Requirement already satisfied: pyyaml in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from pre-commit->visualdl->paddleocr==2.3.0.2) (5.1.2)\n",
      "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from requests->premailer->paddleocr==2.3.0.2) (3.0.4)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from requests->premailer->paddleocr==2.3.0.2) (2019.9.11)\n",
      "Requirement already satisfied: idna<2.9,>=2.5 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from requests->premailer->paddleocr==2.3.0.2) (2.8)\n",
      "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from requests->premailer->paddleocr==2.3.0.2) (1.25.6)\n",
      "Requirement already satisfied: MarkupSafe>=0.23 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from Jinja2>=2.10.1->flask>=1.1.1->visualdl->paddleocr==2.3.0.2) (1.1.1)\n",
      "Requirement already satisfied: zipp>=0.5 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from importlib-metadata->flake8>=3.7.9->visualdl->paddleocr==2.3.0.2) (3.6.0)\n",
      "Installing collected packages: paddleocr\n",
      "Successfully installed paddleocr-2.3.0.2\n"
     ]
    }
   ],
   "source": [
    "!pip install \"paddleocr==2.3.0.2\"\n",
    "\n",
    "# 如果希望获取最新特性，可以基于源码编译安装\n",
    "#     python3 setup.py bdist_wheel\n",
    "#     pip3 install dist/paddleocr-x.x.x-py3-none-any.whl # x.x.x是paddleocr的版本号\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### 2.6.2 使用whl包预测推理\n",
    "\n",
    "paddleocr whl包会自动下载PP-OCRv2超轻量模型作为默认模型，也支持自定义模型路径、预测配置等参数，参数名称与基于Paddle Inference的python预测中参数相同。\n",
    "\n",
    "\n",
    "* 单独执行检测。\n",
    "\n",
    "运行下面的代码，可快速体验文本检测模型的预测与效果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2021/12/25 16:04:56] root WARNING: version PP-OCRv2 not support cls models, auto switch to version PP-OCR\n",
      "download https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_infer.tar to /home/aistudio/.paddleocr/2.3.0.2/ocr/det/ch/ch_PP-OCRv2_det_infer/ch_PP-OCRv2_det_infer.tar\n",
      "download https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar to /home/aistudio/.paddleocr/2.3.0.2/ocr/rec/ch/ch_PP-OCRv2_rec_infer/ch_PP-OCRv2_rec_infer.tar\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 3.19M/3.19M [00:00<00:00, 47.1MiB/s]\n",
      "100%|██████████| 8.88M/8.88M [00:00<00:00, 54.8MiB/s]\n",
      "100%|██████████| 1.45M/1.45M [00:00<00:00, 35.4MiB/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "download https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar to /home/aistudio/.paddleocr/2.3.0.2/ocr/cls/ch_ppocr_mobile_v2.0_cls_infer/ch_ppocr_mobile_v2.0_cls_infer.tar\n",
      "Namespace(benchmark=False, cls_batch_num=6, cls_image_shape='3, 48, 192', cls_model_dir='/home/aistudio/.paddleocr/2.3.0.2/ocr/cls/ch_ppocr_mobile_v2.0_cls_infer', cls_thresh=0.9, cpu_threads=10, crop_res_save_dir='./output', det=True, det_algorithm='DB', det_db_box_thresh=0.6, det_db_score_mode='fast', det_db_thresh=0.3, det_db_unclip_ratio=1.5, det_east_cover_thresh=0.1, det_east_nms_thresh=0.2, det_east_score_thresh=0.8, det_limit_side_len=960, det_limit_type='max', det_model_dir='/home/aistudio/.paddleocr/2.3.0.2/ocr/det/ch/ch_PP-OCRv2_det_infer', det_pse_box_thresh=0.85, det_pse_box_type='box', det_pse_min_area=16, det_pse_scale=1, det_pse_thresh=0, det_sast_nms_thresh=0.2, det_sast_polygon=False, det_sast_score_thresh=0.5, draw_img_save_dir='./inference_results', drop_score=0.5, e2e_algorithm='PGNet', e2e_char_dict_path='./ppocr/utils/ic15_dict.txt', e2e_limit_side_len=768, e2e_limit_type='max', e2e_model_dir=None, e2e_pgnet_mode='fast', e2e_pgnet_score_thresh=0.5, e2e_pgnet_valid_set='totaltext', enable_mkldnn=False, gpu_mem=500, help='==SUPPRESS==', image_dir=None, ir_optim=True, label_list=['0', '180'], label_map_path='./vqa/labels/labels_ser.txt', lang='ch', layout_path_model='lp://PubLayNet/ppyolov2_r50vd_dcn_365e_publaynet/config', max_batch_size=10, max_seq_length=512, max_text_length=25, min_subgraph_size=15, mode='structure', model_name_or_path=None, ocr_version='PP-OCRv2', output='./output', precision='fp32', process_id=0, rec=True, rec_algorithm='CRNN', rec_batch_num=6, rec_char_dict_path='/home/aistudio/PaddleOCR/ppocr/utils/ppocr_keys_v1.txt', rec_image_shape='3, 32, 320', rec_model_dir='/home/aistudio/.paddleocr/2.3.0.2/ocr/rec/ch/ch_PP-OCRv2_rec_infer', save_crop_res=False, save_log_path='./log_output/', show_log=True, structure_version='STRUCTURE', table_char_dict_path=None, table_char_type='en', table_max_len=488, table_model_dir=None, total_process_num=1, type='ocr', use_angle_cls=False, use_dilation=False, use_gpu=False, use_mp=False, use_onnx=False, use_pdserving=False, use_space_char=True, use_tensorrt=False, vis_font_path='./doc/fonts/simfang.ttf', warmup=False)\n",
      "[2021/12/25 16:04:57] root WARNING: Since the angle classifier is not initialized, the angle classifier will not be uesd during the forward process\n",
      "[[27.0, 459.0], [135.0, 459.0], [135.0, 479.0], [27.0, 479.0]]\n",
      "[[29.0, 431.0], [369.0, 431.0], [369.0, 444.0], [29.0, 444.0]]\n",
      "[[26.0, 397.0], [361.0, 397.0], [361.0, 414.0], [26.0, 414.0]]\n",
      "[[369.0, 368.0], [475.0, 368.0], [475.0, 389.0], [369.0, 389.0]]\n",
      "[[28.0, 367.0], [279.0, 367.0], [279.0, 381.0], [28.0, 381.0]]\n",
      "[[27.0, 335.0], [343.0, 335.0], [343.0, 352.0], [27.0, 352.0]]\n",
      "[[26.0, 304.0], [251.0, 304.0], [251.0, 320.0], [26.0, 320.0]]\n",
      "[[24.0, 271.0], [180.0, 269.0], [180.0, 289.0], [24.0, 290.0]]\n",
      "[[24.0, 239.0], [241.0, 238.0], [241.0, 258.0], [24.0, 259.0]]\n",
      "[[413.0, 233.0], [430.0, 233.0], [430.0, 303.0], [413.0, 303.0]]\n",
      "[[25.0, 208.0], [234.0, 208.0], [234.0, 228.0], [25.0, 228.0]]\n",
      "[[25.0, 177.0], [300.0, 177.0], [300.0, 196.0], [25.0, 196.0]]\n",
      "[[26.0, 143.0], [281.0, 144.0], [281.0, 164.0], [26.0, 163.0]]\n",
      "[[28.0, 113.0], [330.0, 113.0], [330.0, 133.0], [28.0, 133.0]]\n",
      "[[27.0, 82.0], [172.0, 82.0], [172.0, 103.0], [27.0, 103.0]]\n",
      "[[28.0, 37.0], [302.0, 39.0], [302.0, 72.0], [28.0, 70.0]]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 197828 characters]",
      "text/plain": [
       "<Figure size 1080x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from paddleocr import PaddleOCR, draw_ocr\n",
    "\n",
    "ocr = PaddleOCR(use_gpu=False)  # need to run only once to download and load model into memory\n",
    "img_path = '/home/aistudio/PaddleOCR/doc/imgs/11.jpg'\n",
    "result = ocr.ocr(img_path, rec=False)\n",
    "for line in result:\n",
    "    print(line)\n",
    "\n",
    "# 显示结果\n",
    "from PIL import Image\n",
    "\n",
    "image = Image.open(img_path).convert('RGB')\n",
    "im_show = draw_ocr(image, result, txts=None, scores=None, font_path='/home/aistudio/PaddleOCR/doc/fonts/simfang.ttf')\n",
    "plt.figure(figsize=(15, 8))\n",
    "plt.imshow(im_show)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "* 单独执行识别\n",
    "\n",
    "可以指定`det=False`，仅运行单独的识别模块。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2021/12/25 16:05:03] root WARNING: version PP-OCRv2 not support cls models, auto switch to version PP-OCR\n",
      "Namespace(benchmark=False, cls_batch_num=6, cls_image_shape='3, 48, 192', cls_model_dir='/home/aistudio/.paddleocr/2.3.0.2/ocr/cls/ch_ppocr_mobile_v2.0_cls_infer', cls_thresh=0.9, cpu_threads=10, crop_res_save_dir='./output', det=True, det_algorithm='DB', det_db_box_thresh=0.6, det_db_score_mode='fast', det_db_thresh=0.3, det_db_unclip_ratio=1.5, det_east_cover_thresh=0.1, det_east_nms_thresh=0.2, det_east_score_thresh=0.8, det_limit_side_len=960, det_limit_type='max', det_model_dir='/home/aistudio/.paddleocr/2.3.0.2/ocr/det/ch/ch_PP-OCRv2_det_infer', det_pse_box_thresh=0.85, det_pse_box_type='box', det_pse_min_area=16, det_pse_scale=1, det_pse_thresh=0, det_sast_nms_thresh=0.2, det_sast_polygon=False, det_sast_score_thresh=0.5, draw_img_save_dir='./inference_results', drop_score=0.5, e2e_algorithm='PGNet', e2e_char_dict_path='./ppocr/utils/ic15_dict.txt', e2e_limit_side_len=768, e2e_limit_type='max', e2e_model_dir=None, e2e_pgnet_mode='fast', e2e_pgnet_score_thresh=0.5, e2e_pgnet_valid_set='totaltext', enable_mkldnn=False, gpu_mem=500, help='==SUPPRESS==', image_dir=None, ir_optim=True, label_list=['0', '180'], label_map_path='./vqa/labels/labels_ser.txt', lang='ch', layout_path_model='lp://PubLayNet/ppyolov2_r50vd_dcn_365e_publaynet/config', max_batch_size=10, max_seq_length=512, max_text_length=25, min_subgraph_size=15, mode='structure', model_name_or_path=None, ocr_version='PP-OCRv2', output='./output', precision='fp32', process_id=0, rec=True, rec_algorithm='CRNN', rec_batch_num=6, rec_char_dict_path='/home/aistudio/PaddleOCR/ppocr/utils/ppocr_keys_v1.txt', rec_image_shape='3, 32, 320', rec_model_dir='/home/aistudio/.paddleocr/2.3.0.2/ocr/rec/ch/ch_PP-OCRv2_rec_infer', save_crop_res=False, save_log_path='./log_output/', show_log=True, structure_version='STRUCTURE', table_char_dict_path=None, table_char_type='en', table_max_len=488, table_model_dir=None, total_process_num=1, type='ocr', use_angle_cls=False, use_dilation=False, use_gpu=False, use_mp=False, use_onnx=False, use_pdserving=False, use_space_char=True, use_tensorrt=False, vis_font_path='./doc/fonts/simfang.ttf', warmup=False)\n",
      "[2021/12/25 16:05:03] root WARNING: Since the angle classifier is not initialized, the angle classifier will not be uesd during the forward process\n",
      "('韩国小馆', 0.9967349)\n"
     ]
    }
   ],
   "source": [
    "from paddleocr import PaddleOCR\n",
    "\n",
    "ocr = PaddleOCR(use_gpu=False)  # need to run only once to download and load model into memory\n",
    "img_path = '/home/aistudio/PaddleOCR/doc/imgs_words/ch/word_1.jpg'\n",
    "result = ocr.ocr(img_path, det=False)\n",
    "for line in result:\n",
    "    print(line)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "* 单独执行方向分类器\n",
    "\n",
    "可以指定`det=False, rec=False, cls=True`，仅运行方向分类器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2021/12/25 16:06:27] root WARNING: version PP-OCRv2 not support cls models, auto switch to version PP-OCR\n",
      "Namespace(benchmark=False, cls_batch_num=6, cls_image_shape='3, 48, 192', cls_model_dir='/home/aistudio/.paddleocr/2.3.0.2/ocr/cls/ch_ppocr_mobile_v2.0_cls_infer', cls_thresh=0.9, cpu_threads=10, crop_res_save_dir='./output', det=True, det_algorithm='DB', det_db_box_thresh=0.6, det_db_score_mode='fast', det_db_thresh=0.3, det_db_unclip_ratio=1.5, det_east_cover_thresh=0.1, det_east_nms_thresh=0.2, det_east_score_thresh=0.8, det_limit_side_len=960, det_limit_type='max', det_model_dir='/home/aistudio/.paddleocr/2.3.0.2/ocr/det/ch/ch_PP-OCRv2_det_infer', det_pse_box_thresh=0.85, det_pse_box_type='box', det_pse_min_area=16, det_pse_scale=1, det_pse_thresh=0, det_sast_nms_thresh=0.2, det_sast_polygon=False, det_sast_score_thresh=0.5, draw_img_save_dir='./inference_results', drop_score=0.5, e2e_algorithm='PGNet', e2e_char_dict_path='./ppocr/utils/ic15_dict.txt', e2e_limit_side_len=768, e2e_limit_type='max', e2e_model_dir=None, e2e_pgnet_mode='fast', e2e_pgnet_score_thresh=0.5, e2e_pgnet_valid_set='totaltext', enable_mkldnn=False, gpu_mem=500, help='==SUPPRESS==', image_dir=None, ir_optim=True, label_list=['0', '180'], label_map_path='./vqa/labels/labels_ser.txt', lang='ch', layout_path_model='lp://PubLayNet/ppyolov2_r50vd_dcn_365e_publaynet/config', max_batch_size=10, max_seq_length=512, max_text_length=25, min_subgraph_size=15, mode='structure', model_name_or_path=None, ocr_version='PP-OCRv2', output='./output', precision='fp32', process_id=0, rec=True, rec_algorithm='CRNN', rec_batch_num=6, rec_char_dict_path='/home/aistudio/PaddleOCR/ppocr/utils/ppocr_keys_v1.txt', rec_image_shape='3, 32, 320', rec_model_dir='/home/aistudio/.paddleocr/2.3.0.2/ocr/rec/ch/ch_PP-OCRv2_rec_infer', save_crop_res=False, save_log_path='./log_output/', show_log=True, structure_version='STRUCTURE', table_char_dict_path=None, table_char_type='en', table_max_len=488, table_model_dir=None, total_process_num=1, type='ocr', use_angle_cls=True, use_dilation=False, use_gpu=False, use_mp=False, use_onnx=False, use_pdserving=False, use_space_char=True, use_tensorrt=False, vis_font_path='./doc/fonts/simfang.ttf', warmup=False)\n",
      "['0', 0.9998784]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 62244 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from paddleocr import PaddleOCR\n",
    "\n",
    "ocr = PaddleOCR(use_angle_cls=True, use_gpu=False)  # need to run only once to download and load model into memory\n",
    "img_path = '/home/aistudio/PaddleOCR/doc/imgs_words/ch/word_1.jpg'\n",
    "result = ocr.ocr(img_path, det=False, rec=False, cls=True)\n",
    "for line in result:\n",
    "    print(line)\n",
    "\n",
    "img = cv2.imread(img_path)\n",
    "plt.imshow(img[...,::-1])\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "* `检测+方向分类器+识别`全流程体验\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2021/12/25 16:07:58] root WARNING: version PP-OCRv2 not support cls models, auto switch to version PP-OCR\n",
      "Namespace(benchmark=False, cls_batch_num=6, cls_image_shape='3, 48, 192', cls_model_dir='/home/aistudio/.paddleocr/2.3.0.2/ocr/cls/ch_ppocr_mobile_v2.0_cls_infer', cls_thresh=0.9, cpu_threads=10, crop_res_save_dir='./output', det=True, det_algorithm='DB', det_db_box_thresh=0.6, det_db_score_mode='fast', det_db_thresh=0.3, det_db_unclip_ratio=1.5, det_east_cover_thresh=0.1, det_east_nms_thresh=0.2, det_east_score_thresh=0.8, det_limit_side_len=960, det_limit_type='max', det_model_dir='/home/aistudio/.paddleocr/2.3.0.2/ocr/det/ch/ch_PP-OCRv2_det_infer', det_pse_box_thresh=0.85, det_pse_box_type='box', det_pse_min_area=16, det_pse_scale=1, det_pse_thresh=0, det_sast_nms_thresh=0.2, det_sast_polygon=False, det_sast_score_thresh=0.5, draw_img_save_dir='./inference_results', drop_score=0.5, e2e_algorithm='PGNet', e2e_char_dict_path='./ppocr/utils/ic15_dict.txt', e2e_limit_side_len=768, e2e_limit_type='max', e2e_model_dir=None, e2e_pgnet_mode='fast', e2e_pgnet_score_thresh=0.5, e2e_pgnet_valid_set='totaltext', enable_mkldnn=False, gpu_mem=500, help='==SUPPRESS==', image_dir=None, ir_optim=True, label_list=['0', '180'], label_map_path='./vqa/labels/labels_ser.txt', lang='ch', layout_path_model='lp://PubLayNet/ppyolov2_r50vd_dcn_365e_publaynet/config', max_batch_size=10, max_seq_length=512, max_text_length=25, min_subgraph_size=15, mode='structure', model_name_or_path=None, ocr_version='PP-OCRv2', output='./output', precision='fp32', process_id=0, rec=True, rec_algorithm='CRNN', rec_batch_num=6, rec_char_dict_path='/home/aistudio/PaddleOCR/ppocr/utils/ppocr_keys_v1.txt', rec_image_shape='3, 32, 320', rec_model_dir='/home/aistudio/.paddleocr/2.3.0.2/ocr/rec/ch/ch_PP-OCRv2_rec_infer', save_crop_res=False, save_log_path='./log_output/', show_log=True, structure_version='STRUCTURE', table_char_dict_path=None, table_char_type='en', table_max_len=488, table_model_dir=None, total_process_num=1, type='ocr', use_angle_cls=True, use_dilation=False, use_gpu=False, use_mp=False, use_onnx=False, use_pdserving=False, use_space_char=True, use_tensorrt=False, vis_font_path='./doc/fonts/simfang.ttf', warmup=False)\n",
      "[2021/12/25 16:08:00] root DEBUG: dt_boxes num : 16, elapse : 1.1848454475402832\n",
      "[2021/12/25 16:08:01] root DEBUG: cls num  : 16, elapse : 0.7081763744354248\n",
      "[2021/12/25 16:08:08] root DEBUG: rec_res num  : 16, elapse : 7.406725883483887\n",
      "[[[28.0, 37.0], [302.0, 39.0], [302.0, 72.0], [28.0, 70.0]], ('纯臻营养护发素', 0.9924613)]\n",
      "[[[27.0, 82.0], [172.0, 82.0], [172.0, 103.0], [27.0, 103.0]], ('产品信息/参数', 0.992365)]\n",
      "[[[28.0, 113.0], [330.0, 113.0], [330.0, 133.0], [28.0, 133.0]], ('（45元/每公斤，100公斤起订）', 0.90023524)]\n",
      "[[[26.0, 143.0], [281.0, 144.0], [281.0, 164.0], [26.0, 163.0]], ('每瓶22元，1000瓶起订）', 0.9793598)]\n",
      "[[[25.0, 177.0], [300.0, 177.0], [300.0, 196.0], [25.0, 196.0]], ('【品牌】：代加工方式/OEMODM', 0.98173994)]\n",
      "[[[25.0, 208.0], [234.0, 208.0], [234.0, 228.0], [25.0, 228.0]], ('【品名】：纯臻营养护发素', 0.9742198)]\n",
      "[[[24.0, 239.0], [241.0, 238.0], [241.0, 258.0], [24.0, 259.0]], ('【产品编号】：YM-X-3011', 0.9428464)]\n",
      "[[[413.0, 233.0], [430.0, 233.0], [430.0, 303.0], [413.0, 303.0]], ('ODM OEM', 0.91271496)]\n",
      "[[[24.0, 271.0], [180.0, 269.0], [180.0, 289.0], [24.0, 290.0]], ('【净含量】：220ml', 0.97186875)]\n",
      "[[[26.0, 304.0], [251.0, 304.0], [251.0, 320.0], [26.0, 320.0]], ('【适用人群】：适合所有肤质', 0.94716364)]\n",
      "[[[27.0, 335.0], [343.0, 335.0], [343.0, 352.0], [27.0, 352.0]], ('（主要成分】：鲸蜡硬脂醇、燕麦B-葡聚', 0.89800084)]\n",
      "[[[28.0, 367.0], [279.0, 367.0], [279.0, 381.0], [28.0, 381.0]], ('糖、椰油酰胺丙基甜菜碱泛醒', 0.8583736)]\n",
      "[[[369.0, 368.0], [475.0, 368.0], [475.0, 389.0], [369.0, 389.0]], ('（成品包材）', 0.971282)]\n",
      "[[[26.0, 397.0], [361.0, 397.0], [361.0, 414.0], [26.0, 414.0]], ('主要功能】：可紧致头发磷层，从而达到', 0.97077614)]\n",
      "[[[29.0, 431.0], [369.0, 431.0], [369.0, 444.0], [29.0, 444.0]], ('即时持久改善头发光泽的效果，给干燥的头', 0.9430727)]\n",
      "[[[27.0, 459.0], [135.0, 459.0], [135.0, 479.0], [27.0, 479.0]], ('发足够的滋养', 0.97956467)]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 289932 characters]",
      "text/plain": [
       "<Figure size 1080x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from paddleocr import PaddleOCR, draw_ocr\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "# PaddleOCR目前支持中英文、英文、法语、德语、韩语、日语，可以通过修改lang参数进行切换\n",
    "# 参数依次为`ch`, `en`, `french`, `german`, `korean`, `japan`。\n",
    "ocr = PaddleOCR(use_angle_cls=True, lang=\"ch\", use_gpu=False)  # need to run only once to download and load model into memory\n",
    "img_path = '/home/aistudio/PaddleOCR/doc/imgs/11.jpg'\n",
    "result = ocr.ocr(img_path, cls=True)\n",
    "for line in result:\n",
    "    print(line)\n",
    "\n",
    "# 显示结果\n",
    "from PIL import Image\n",
    "\n",
    "image = Image.open(img_path).convert('RGB')\n",
    "boxes = [line[0] for line in result]\n",
    "txts = [line[1][0] for line in result]\n",
    "scores = [line[1][1] for line in result]\n",
    "im_show = draw_ocr(image, boxes, txts, scores, font_path='/home/aistudio/PaddleOCR/doc/fonts/simfang.ttf')\n",
    "plt.figure(figsize=(15, 8))\n",
    "plt.imshow(im_show)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "结果是一个list，每个item包含了文本框，文字和识别置信度。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "# 3. 基于Paddle Inference的C++推理\n",
    "\n",
    "在推理部署过程中，相比于Python，C++的性能一般会更好一些，因此很多实际推理场景中会考虑使用C++作为开发语言进行推理。\n",
    "\n",
    "上一小节给大家介绍的Paddle Inference也支持C++的推理过程，本节主要介绍C++的PP-OCRv2推理过程。\n",
    "\n",
    "在基于Paddle Inference，对PP-OCRv2系统使用C++推理时，有以下几个步骤。\n",
    "\n",
    "（1）准备模型\n",
    "\n",
    "（2）编译opencv库\n",
    "\n",
    "（3）获取Paddle Inference预测库\n",
    "\n",
    "（4）编译PaddleOCR C++推理代码\n",
    "\n",
    "（5）运行PP-OCRv2系统\n",
    "\n",
    "由于AiStudio上版本限制，这里不做具体演示过程，仅给大家介绍具体的流程。建议您在本地体验PP-OCRv2的C++推理过程。\n",
    "\n",
    "关于本小节更加详细的内容可以参考：[PP-OCRv2 C++推理教程](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.4/deploy/cpp_infer/readme.md)。\n",
    "\n",
    "## 3.1 准备模型\n",
    "\n",
    "使用下面的命令，准备PP-OCRv2的推理模型。\n",
    "\n",
    "```bash\n",
    "cd deploy/cpp_infer\n",
    "wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_infer.tar -O ch_PP-OCRv2_det_infer.tar && tar -xf ch_PP-OCRv2_det_infer.tar\n",
    "wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar -O ch_PP-OCRv2_rec_infer.tar &&  tar -xf ch_PP-OCRv2_rec_infer.tar\n",
    "wget https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar -O ch_ppocr_mobile_v2.0_cls_infer.tar && tar -xf ch_ppocr_mobile_v2.0_cls_infer.tar\n",
    "```\n",
    "\n",
    "## 3.2 编译OpenCV库\n",
    "\n",
    "* 首先需要从opencv官网上下载在Linux环境下源码编译的包，以opencv3.4.7为例，下载命令如下。\n",
    "\n",
    "```bash\n",
    "wget https://paddleocr.bj.bcebos.com/libs/opencv/opencv-3.4.7.tar.gz\n",
    "tar -xf opencv-3.4.7.tar.gz\n",
    "```\n",
    "\n",
    "最终可以在当前目录下看到`opencv-3.4.7/`的文件夹。\n",
    "\n",
    "* 编译OpenCV，设置OpenCV源码路径(`root_path`)以及安装路径(`install_path`)。进入opencv源码路径下，按照下面的方式进行编译。\n",
    "\n",
    "```shell\n",
    "root_path=\"your_opencv_root_path\"\n",
    "install_path=${root_path}/opencv3\n",
    "build_dir=${root_path}/build\n",
    "\n",
    "rm -rf ${build_dir}\n",
    "mkdir ${build_dir}\n",
    "cd ${build_dir}\n",
    "\n",
    "cmake .. \\\n",
    "    -DCMAKE_INSTALL_PREFIX=${install_path} \\\n",
    "    -DCMAKE_BUILD_TYPE=Release \\\n",
    "    -DBUILD_SHARED_LIBS=OFF \\\n",
    "    -DWITH_IPP=OFF \\\n",
    "    -DBUILD_IPP_IW=OFF \\\n",
    "    -DWITH_LAPACK=OFF \\\n",
    "    -DWITH_EIGEN=OFF \\\n",
    "    -DCMAKE_INSTALL_LIBDIR=lib64 \\\n",
    "    -DWITH_ZLIB=ON \\\n",
    "    -DBUILD_ZLIB=ON \\\n",
    "    -DWITH_JPEG=ON \\\n",
    "    -DBUILD_JPEG=ON \\\n",
    "    -DWITH_PNG=ON \\\n",
    "    -DBUILD_PNG=ON \\\n",
    "    -DWITH_TIFF=ON \\\n",
    "    -DBUILD_TIFF=ON\n",
    "\n",
    "make -j\n",
    "make install\n",
    "```\n",
    "\n",
    "也可以直接修改`tools/build_opencv.sh`的内容，然后直接运行下面的命令进行编译。\n",
    "\n",
    "```shell\n",
    "sh tools/build_opencv.sh\n",
    "```\n",
    "\n",
    "其中`root_path`为下载的opencv源码路径，`install_path`为opencv的安装路径，`make install`完成之后，会在该文件夹下生成opencv头文件和库文件，用于后面的OCR代码编译。\n",
    "\n",
    "最终在安装路径下的文件结构如下所示。\n",
    "\n",
    "```\n",
    "opencv3/\n",
    "|-- bin\n",
    "|-- include\n",
    "|-- lib\n",
    "|-- lib64\n",
    "|-- share\n",
    "```\n",
    "\n",
    "## 3.3 获取Paddle Inference预测库\n",
    "\n",
    "* [Paddle预测库官网](https://paddle-inference.readthedocs.io/en/latest/user_guides/download_lib.html) 上提供了不同cuda版本的Linux预测库，可以在官网根据自己的环境选择合适的预测库版本。\n",
    "\n",
    "* 下载之后使用下面的方法解压。\n",
    "\n",
    "```bash\n",
    "wget https://paddle-inference-lib.bj.bcebos.com/2.2.1/cxx_c/Linux/GPU/x86-64_gcc8.2_avx_mkl_cuda10.2_cudnn8.1.1_trt7.2.3.4/paddle_inference.tgz -O paddle_inference.tgz\n",
    "tar -xf paddle_inference.tgz\n",
    "```\n",
    "\n",
    "最终会在当前的文件夹中生成`paddle_inference/`的子文件夹。\n",
    "\n",
    "## 3.4 编译PaddleOCR的推理代码\n",
    "\n",
    "编译命令如下，其中Paddle C++预测库、opencv等其他依赖库的地址需要换成自己机器上的实际地址。\n",
    "\n",
    "```shell\n",
    "sh tools/build.sh\n",
    "```\n",
    "\n",
    "* 具体的，需要修改`tools/build.sh`中环境路径，相关内容如下：\n",
    "\n",
    "```shell\n",
    "OPENCV_DIR=your_opencv_dir\n",
    "LIB_DIR=your_paddle_inference_dir\n",
    "CUDA_LIB_DIR=your_cuda_lib_dir\n",
    "CUDNN_LIB_DIR=/your_cudnn_lib_dir\n",
    "```\n",
    "\n",
    "其中，`OPENCV_DIR`为opencv编译安装的地址；`LIB_DIR`为下载(`paddle_inference`文件夹)或者编译生成的Paddle预测库地址(`build/paddle_inference_install_dir`文件夹)；`CUDA_LIB_DIR`为cuda库文件地址，在docker中为`/usr/local/cuda/lib64`；`CUDNN_LIB_DIR`为cudnn库文件地址，在docker中为`/usr/lib/x86_64-linux-gnu/`。**注意：以上路径都写绝对路径，不要写相对路径。**\n",
    "\n",
    "* 编译完成之后，会在`build`文件夹下生成一个名为`ppocr`的可执行文件。\n",
    "\n",
    "## 3.5 运行PP-OCRv2系统\n",
    "\n",
    "运行方式：  \n",
    "```shell\n",
    "./build/ppocr <mode> [--param1] [--param2] [...]\n",
    "```\n",
    "其中，`mode`为必选参数，表示选择的功能，取值范围['det', 'rec', 'system']，分别表示调用检测、识别、检测识别串联（包括方向分类器）。具体命令如下：\n",
    "\n",
    "* 只运行文字检测模型\n",
    "\n",
    "```bash\n",
    "./build/ppocr det \\\n",
    "    --det_model_dir=./ch_PP-OCRv2_det_infer/ \\\n",
    "    --image_dir=../../doc/imgs/12.jpg\n",
    "```\n",
    "* 只运行文字识别模型\n",
    "\n",
    "```shell\n",
    "./build/ppocr rec \\\n",
    "    --rec_model_dir=./ch_PP-OCRv2_rec_infer/ \\\n",
    "    --image_dir=../../doc/imgs_words/ch/\n",
    "```\n",
    "* 运行PP-OCRv2系统\n",
    "\n",
    "```shell\n",
    "# 不使用方向分类器\n",
    "./build/ppocr system \\\n",
    "    --det_model_dir=./ch_PP-OCRv2_det_infer/ \\\n",
    "    --rec_model_dir=./ch_PP-OCRv2_rec_infer/ \\\n",
    "    --image_dir=../../doc/imgs/12.jpg\n",
    "\n",
    "# 使用方向分类器\n",
    "./build/ppocr system \\\n",
    "    --det_model_dir=./ch_PP-OCRv2_det_infer/ \\\n",
    "    --rec_model_dir=./ch_PP-OCRv2_rec_infer/ \\\n",
    "    --use_angle_cls=true \\\n",
    "    --cls_model_dir=./ch_ppocr_mobile_v2.0_cls_infer \\\n",
    "    --image_dir=../../doc/imgs/12.jpg\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "#  4. Paddle Serving服务化部署实战\n",
    "\n",
    "在第2和第3节内容中，我们详细介绍了基于Paddle Inference的PP-OCRv2系统推理，它属于离线推理，即在特定机器上部署的代码只能在这台机器上使用，无法通过其他机器进行访问。因此模型服务化部署的需求也就衍生出来。\n",
    "\n",
    "服务化部署指的是，将模型以服务的形式进行部署，其他的设备可以通过发送请求的形式去访问服务，从而获取模型服务的推理结果。服务化部署示意图如下所示。\n",
    "\n",
    "<div align=\"center\">\n",
    "<img src=\"https://ai-studio-static-online.cdn.bcebos.com/831abb70838e456fb2cec236817b9c5b1a0dff15fff7479e8f8430493c4506ea\"  width = \"400\" />\n",
    "</div>\n",
    "<center>服务化部署示意图</center>\n",
    "\n",
    "在模型部署成功后，不同用户都可以通过客户端，以发送网络请求的方式获得推理服务。\n",
    "\n",
    "Paddle Serving是飞桨为方便开发者进行服务化部署而打造的工具，本节主要介绍基于Paddle Serving的PP-OCRv2系统服务化部署过程。\n",
    "\n",
    "## 4.1 Paddle Serving简介\n",
    "\n",
    "Paddle Serving作为飞桨（PaddlePaddle）开源的服务化部署框架，长期目标就是围绕着人工智能落地的最后一公里提供越来越专业、可靠、易用的服务。Paddle Serving目前提供了两套框架C++ Serving和Python Pipeline。Python Pipeline框架倾向于二次开发的便捷性，C++ Serving框架更倾向于追求极致性能。\n",
    "\n",
    "基于Paddle Serving进行PP-OCRv2模型的服务化部署时，流程如下所示。\n",
    "\n",
    "<div align=\"center\">\n",
    "<img src=\"https://ai-studio-static-online.cdn.bcebos.com/348c446f79a04bca8801b5fc6dd3c5d5207711179d4d4d9db15e8cb4b1bd8810\"  width = \"800\" />\n",
    "</div>\n",
    "<center>基于Paddle Serving部署PP-OCRv2系统流程图</center>\n",
    "\n",
    "\n",
    "## 4.2 准备预测数据和部署环境\n",
    "\n",
    "数据与模型推理所用数据一致。\n",
    "\n",
    "运行Paddle Serving，需要安装Paddle Serving三个安装包：paddle-serving-server、paddle-serving-client 和 paddle-serving-app，命令如下。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2021-12-25 16:25:12--  https://paddle-serving.bj.bcebos.com/test-dev/whl/paddle_serving_server_gpu-0.7.0.post102-py3-none-any.whl\n",
      "Resolving paddle-serving.bj.bcebos.com (paddle-serving.bj.bcebos.com)... 100.67.200.6\n",
      "Connecting to paddle-serving.bj.bcebos.com (paddle-serving.bj.bcebos.com)|100.67.200.6|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 7146257 (6.8M) [application/octet-stream]\n",
      "Saving to: ‘paddle_serving_server_gpu-0.7.0.post102-py3-none-any.whl’\n",
      "\n",
      "paddle_serving_serv 100%[===================>]   6.81M  --.-KB/s    in 0.1s    \n",
      "\n",
      "2021-12-25 16:25:12 (57.6 MB/s) - ‘paddle_serving_server_gpu-0.7.0.post102-py3-none-any.whl’ saved [7146257/7146257]\n",
      "\n",
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple\n",
      "Processing ./paddle_serving_server_gpu-0.7.0.post102-py3-none-any.whl\n",
      "Collecting Jinja2==2.11.3\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/7e/c2/1eece8c95ddbc9b1aeb64f5783a9e07a286de42191b7204d67b7496ddf35/Jinja2-2.11.3-py2.py3-none-any.whl (125 kB)\n",
      "     |████████████████████████████████| 125 kB 14.9 MB/s            \n",
      "\u001b[?25hCollecting func-timeout\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/b3/0d/bf0567477f7281d9a3926c582bfef21bff7498fc0ffd3e9de21811896a0b/func_timeout-4.3.5.tar.gz (44 kB)\n",
      "     |████████████████████████████████| 44 kB 6.3 MB/s             \n",
      "\u001b[?25h  Preparing metadata (setup.py) ... \u001b[?25ldone\n",
      "\u001b[?25hRequirement already satisfied: six>=1.10.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-server-gpu==0.7.0.post102) (1.15.0)\n",
      "Requirement already satisfied: itsdangerous==1.1.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-server-gpu==0.7.0.post102) (1.1.0)\n",
      "Requirement already satisfied: MarkupSafe==1.1.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-server-gpu==0.7.0.post102) (1.1.1)\n",
      "Collecting Werkzeug==1.0.1\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/cc/94/5f7079a0e00bd6863ef8f1da638721e9da21e5bacee597595b318f71d62e/Werkzeug-1.0.1-py2.py3-none-any.whl (298 kB)\n",
      "     |████████████████████████████████| 298 kB 20.6 MB/s            \n",
      "\u001b[?25hRequirement already satisfied: protobuf>=3.11.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-server-gpu==0.7.0.post102) (3.14.0)\n",
      "Collecting grpcio<=1.33.2\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/7a/46/d08d8a5d0e0449f541fe9e7a226854019a41a4fa41fd14332e55b0e4394f/grpcio-1.33.2-cp37-cp37m-manylinux2014_x86_64.whl (3.8 MB)\n",
      "     |████████████████████████████████| 3.8 MB 82.7 MB/s            \n",
      "\u001b[?25hCollecting grpcio-tools<=1.33.2\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/77/1e/91eaee901589ebee04c21df2f551502e7ba946bab99338f77a1f8a4237e1/grpcio_tools-1.33.2-cp37-cp37m-manylinux2014_x86_64.whl (2.5 MB)\n",
      "     |████████████████████████████████| 2.5 MB 2.7 MB/s            \n",
      "\u001b[?25hCollecting click==7.1.2\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/d2/3d/fa76db83bf75c4f8d338c2fd15c8d33fdd7ad23a9b5e57eb6c5de26b430e/click-7.1.2-py2.py3-none-any.whl (82 kB)\n",
      "     |████████████████████████████████| 82 kB 2.6 MB/s             \n",
      "\u001b[?25hRequirement already satisfied: flask<2.0.0,>=1.1.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-server-gpu==0.7.0.post102) (1.1.1)\n",
      "Requirement already satisfied: pyyaml in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-server-gpu==0.7.0.post102) (5.1.2)\n",
      "Building wheels for collected packages: func-timeout\n",
      "  Building wheel for func-timeout (setup.py) ... \u001b[?25ldone\n",
      "\u001b[?25h  Created wheel for func-timeout: filename=func_timeout-4.3.5-py3-none-any.whl size=15077 sha256=787d26c33bea8918d151100cf0cd6c5953b1b065c427075198f1610f8788274d\n",
      "  Stored in directory: /home/aistudio/.cache/pip/wheels/ea/6b/56/b7bcacbd1bd8cd29883e7f7a29cbd98b87b2d789b25bae5563\n",
      "Successfully built func-timeout\n",
      "Installing collected packages: Werkzeug, Jinja2, grpcio, click, grpcio-tools, func-timeout, paddle-serving-server-gpu\n",
      "  Attempting uninstall: Werkzeug\n",
      "    Found existing installation: Werkzeug 0.16.0\n",
      "    Uninstalling Werkzeug-0.16.0:\n",
      "      Successfully uninstalled Werkzeug-0.16.0\n",
      "  Attempting uninstall: Jinja2\n",
      "    Found existing installation: Jinja2 2.11.0\n",
      "    Uninstalling Jinja2-2.11.0:\n",
      "      Successfully uninstalled Jinja2-2.11.0\n",
      "  Attempting uninstall: grpcio\n",
      "    Found existing installation: grpcio 1.35.0\n",
      "    Uninstalling grpcio-1.35.0:\n",
      "      Successfully uninstalled grpcio-1.35.0\n",
      "  Attempting uninstall: click\n",
      "    Found existing installation: Click 7.0\n",
      "    Uninstalling Click-7.0:\n",
      "      Successfully uninstalled Click-7.0\n",
      "ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
      "blackhole 1.0.1 requires numpy<=1.19.5, but you have numpy 1.20.3 which is incompatible.\n",
      "Successfully installed Jinja2-2.11.3 Werkzeug-1.0.1 click-7.1.2 func-timeout-4.3.5 grpcio-1.33.2 grpcio-tools-1.33.2 paddle-serving-server-gpu-0.7.0.post102\n",
      "--2021-12-25 16:25:19--  https://paddle-serving.bj.bcebos.com/test-dev/whl/paddle_serving_client-0.7.0-cp37-none-any.whl\n",
      "Resolving paddle-serving.bj.bcebos.com (paddle-serving.bj.bcebos.com)... 100.67.200.6\n",
      "Connecting to paddle-serving.bj.bcebos.com (paddle-serving.bj.bcebos.com)|100.67.200.6|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 44311645 (42M) [application/octet-stream]\n",
      "Saving to: ‘paddle_serving_client-0.7.0-cp37-none-any.whl’\n",
      "\n",
      "paddle_serving_clie 100%[===================>]  42.26M  66.9MB/s    in 0.6s    \n",
      "\n",
      "2021-12-25 16:25:20 (66.9 MB/s) - ‘paddle_serving_client-0.7.0-cp37-none-any.whl’ saved [44311645/44311645]\n",
      "\n",
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple\n",
      "Processing ./paddle_serving_client-0.7.0-cp37-none-any.whl\n",
      "Requirement already satisfied: six>=1.10.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-client==0.7.0) (1.15.0)\n",
      "Requirement already satisfied: requests in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-client==0.7.0) (2.22.0)\n",
      "Requirement already satisfied: grpcio-tools<=1.33.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-client==0.7.0) (1.33.2)\n",
      "Requirement already satisfied: grpcio<=1.33.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-client==0.7.0) (1.33.2)\n",
      "Requirement already satisfied: protobuf>=3.11.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-client==0.7.0) (3.14.0)\n",
      "Requirement already satisfied: numpy>=1.12 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-client==0.7.0) (1.20.3)\n",
      "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from requests->paddle-serving-client==0.7.0) (1.25.6)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from requests->paddle-serving-client==0.7.0) (2019.9.11)\n",
      "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from requests->paddle-serving-client==0.7.0) (3.0.4)\n",
      "Requirement already satisfied: idna<2.9,>=2.5 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from requests->paddle-serving-client==0.7.0) (2.8)\n",
      "Installing collected packages: paddle-serving-client\n",
      "Successfully installed paddle-serving-client-0.7.0\n",
      "--2021-12-25 16:25:23--  https://paddle-serving.bj.bcebos.com/test-dev/whl/paddle_serving_app-0.7.0-py3-none-any.whl\n",
      "Resolving paddle-serving.bj.bcebos.com (paddle-serving.bj.bcebos.com)... 100.67.200.6\n",
      "Connecting to paddle-serving.bj.bcebos.com (paddle-serving.bj.bcebos.com)|100.67.200.6|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 54130 (53K) [application/octet-stream]\n",
      "Saving to: ‘paddle_serving_app-0.7.0-py3-none-any.whl’\n",
      "\n",
      "paddle_serving_app- 100%[===================>]  52.86K  --.-KB/s    in 0.002s  \n",
      "\n",
      "2021-12-25 16:25:23 (27.6 MB/s) - ‘paddle_serving_app-0.7.0-py3-none-any.whl’ saved [54130/54130]\n",
      "\n",
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple\n",
      "Processing ./paddle_serving_app-0.7.0-py3-none-any.whl\n",
      "Collecting sentencepiece<=0.1.92\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/1e/05/8d8d8fc7ef89d36bbdc9b4ff808def3db0dd52658e67f16779eb05ddb558/sentencepiece-0.1.92-cp37-cp37m-manylinux1_x86_64.whl (1.2 MB)\n",
      "     |████████████████████████████████| 1.2 MB 25.9 MB/s            \n",
      "\u001b[?25hRequirement already satisfied: opencv-python<=4.2.0.32 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-app==0.7.0) (4.1.1.26)\n",
      "Requirement already satisfied: six>=1.10.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-app==0.7.0) (1.15.0)\n",
      "Requirement already satisfied: pyclipper in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-app==0.7.0) (1.3.0.post2)\n",
      "Requirement already satisfied: pillow in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-app==0.7.0) (7.1.2)\n",
      "Requirement already satisfied: shapely in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from paddle-serving-app==0.7.0) (1.8.0)\n",
      "Requirement already satisfied: numpy>=1.14.5 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from opencv-python<=4.2.0.32->paddle-serving-app==0.7.0) (1.20.3)\n",
      "Installing collected packages: sentencepiece, paddle-serving-app\n",
      "  Attempting uninstall: sentencepiece\n",
      "    Found existing installation: sentencepiece 0.1.96\n",
      "    Uninstalling sentencepiece-0.1.96:\n",
      "      Successfully uninstalled sentencepiece-0.1.96\n",
      "Successfully installed paddle-serving-app-0.7.0 sentencepiece-0.1.92\n"
     ]
    }
   ],
   "source": [
    "!wget https://paddle-serving.bj.bcebos.com/test-dev/whl/paddle_serving_server_gpu-0.7.0.post102-py3-none-any.whl\n",
    "!pip install paddle_serving_server_gpu-0.7.0.post102-py3-none-any.whl\n",
    "\n",
    "!wget https://paddle-serving.bj.bcebos.com/test-dev/whl/paddle_serving_client-0.7.0-cp37-none-any.whl\n",
    "!pip install paddle_serving_client-0.7.0-cp37-none-any.whl\n",
    "\n",
    "!wget https://paddle-serving.bj.bcebos.com/test-dev/whl/paddle_serving_app-0.7.0-py3-none-any.whl\n",
    "!pip install paddle_serving_app-0.7.0-py3-none-any.whl\n",
    "\n",
    "!rm ./*.whl"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "## 4.3 准备部署模型\n",
    "\n",
    "在进行模型服务化部署时，首先需要将推理模型转为用户服务化部署的模型。\n",
    "\n",
    "首先运行下面的命令下载推理模型。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2021-12-25 16:25:32--  https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_infer.tar\n",
      "Resolving paddleocr.bj.bcebos.com (paddleocr.bj.bcebos.com)... 100.67.200.6\n",
      "Connecting to paddleocr.bj.bcebos.com (paddleocr.bj.bcebos.com)|100.67.200.6|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 3190272 (3.0M) [application/x-tar]\n",
      "Saving to: ‘ch_PP-OCRv2_det_infer.tar’\n",
      "\n",
      "ch_PP-OCRv2_det_inf 100%[===================>]   3.04M  --.-KB/s    in 0.09s   \n",
      "\n",
      "2021-12-25 16:25:32 (35.0 MB/s) - ‘ch_PP-OCRv2_det_infer.tar’ saved [3190272/3190272]\n",
      "\n",
      "--2021-12-25 16:25:33--  https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar\n",
      "Resolving paddleocr.bj.bcebos.com (paddleocr.bj.bcebos.com)... 100.67.200.6\n",
      "Connecting to paddleocr.bj.bcebos.com (paddleocr.bj.bcebos.com)|100.67.200.6|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 8875520 (8.5M) [application/x-tar]\n",
      "Saving to: ‘ch_PP-OCRv2_rec_infer.tar’\n",
      "\n",
      "ch_PP-OCRv2_rec_inf 100%[===================>]   8.46M  --.-KB/s    in 0.1s    \n",
      "\n",
      "2021-12-25 16:25:33 (69.0 MB/s) - ‘ch_PP-OCRv2_rec_infer.tar’ saved [8875520/8875520]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "os.chdir(\"/home/aistudio/PaddleOCR/deploy/pdserving/\")\n",
    "\n",
    "# 下载并解压 OCR 文本检测模型\n",
    "!wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_infer.tar -O ch_PP-OCRv2_det_infer.tar && tar -xf ch_PP-OCRv2_det_infer.tar && rm ch_PP-OCRv2_det_infer.tar\n",
    "# 下载并解压 OCR 文本识别模型\n",
    "!wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar -O ch_PP-OCRv2_rec_infer.tar &&  tar -xf ch_PP-OCRv2_rec_infer.tar && rm ch_PP-OCRv2_rec_infer.tar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "运行下面的命令进行模型转换。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ppocrv2_det_client\r\n",
      "├── [ 296]  serving_client_conf.prototxt\r\n",
      "└── [  98]  serving_client_conf.stream.prototxt\r\n",
      "ppocrv2_rec_client\r\n",
      "├── [ 284]  serving_client_conf.prototxt\r\n",
      "└── [  93]  serving_client_conf.stream.prototxt\r\n",
      "ppocrv2_det_serving\r\n",
      "├── [2.2M]  inference.pdiparams\r\n",
      "├── [842K]  inference.pdmodel\r\n",
      "├── [ 296]  serving_server_conf.prototxt\r\n",
      "└── [  98]  serving_server_conf.stream.prototxt\r\n",
      "ppocrv2_rec_serving\r\n",
      "├── [7.9M]  inference.pdiparams\r\n",
      "├── [527K]  inference.pdmodel\r\n",
      "├── [ 284]  serving_server_conf.prototxt\r\n",
      "└── [  93]  serving_server_conf.stream.prototxt\r\n",
      "\r\n",
      "0 directories, 12 files\r\n"
     ]
    }
   ],
   "source": [
    "# 转换检测模型\n",
    "!python -m paddle_serving_client.convert --dirname ./ch_PP-OCRv2_det_infer/ \\\n",
    "                                         --model_filename inference.pdmodel          \\\n",
    "                                         --params_filename inference.pdiparams       \\\n",
    "                                         --serving_server ./ppocrv2_det_serving/ \\\n",
    "                                         --serving_client ./ppocrv2_det_client/\n",
    "\n",
    "# 转换识别模型\n",
    "!python -m paddle_serving_client.convert --dirname ./ch_PP-OCRv2_rec_infer/ \\\n",
    "                                         --model_filename inference.pdmodel          \\\n",
    "                                         --params_filename inference.pdiparams       \\\n",
    "                                         --serving_server ./ppocrv2_rec_serving/  \\\n",
    "                                         --serving_client ./ppocrv2_rec_client/\n",
    "\n",
    "# 查看文件夹\n",
    "!tree -h *_client *_serving"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "检测模型转换完成后，会在当前文件夹多出`ppocrv2_det_mobile_serving` 和`ppocrv2_det_mobile_client`的文件夹，具备如下格式：\n",
    "\n",
    "```\n",
    "|- ppocrv2_det_mobile_serving/\n",
    "  |- __model__  \n",
    "  |- __params__\n",
    "  |- serving_server_conf.prototxt  \n",
    "  |- serving_server_conf.stream.prototxt\n",
    "\n",
    "|- ppocrv2_det_mobile_client\n",
    "  |- serving_client_conf.prototxt  \n",
    "  |- serving_client_conf.stream.prototxt\n",
    "\n",
    "```\n",
    "\n",
    "识别模型同理。\n",
    "\n",
    "## 4.4 Paddle Serving pipeline部署\n",
    "\n",
    "**注意**： 将PaddleOCR/deploy/pdserving/config.yml文件中的两个`model_config`字段分别修改为ppocrv2_det_mobile_serving、ppocrv2_rec_mobile_serving，对应模型转换的文件夹。\n",
    "\n",
    "    pdserving目录包含启动pipeline服务和发送预测请求的代码，包括：\n",
    "    ```\n",
    "    __init__.py\n",
    "    config.yml            # 启动服务的配置文件\n",
    "    ocr_reader.py         # OCR模型预处理和后处理的代码实现\n",
    "    pipeline_http_client.py   # 发送预测请求的脚本\n",
    "    web_service.py        # 启动服务端的脚本\n",
    "    ```\n",
    "\n",
    "### 4.4.1 启动服务\n",
    "\n",
    "运行如下命令启动服务：\n",
    "\n",
    "**开启新的终端运行下列启动服务的命令**\n",
    "\n",
    "    ```\n",
    "    # 启动服务，运行日志保存在web_serving_log.txt\n",
    "    cd PaddleOCR/deploy/pdserving/\n",
    "    nohup python web_service.py &>web_serving_log.txt &\n",
    "    ```\n",
    "成功启动服务后，web_serving_log.txt中会打印类似如下日志\n",
    "\n",
    "<div align=\"center\">\n",
    "<img src=\"https://ai-studio-static-online.cdn.bcebos.com/58b32c0158f34a739f9d4b5246b68575519543c786044c19849ab43246f1b482\"  width = \"800\" />\n",
    "</div>\n",
    "<center>服务端日志</center>\n",
    "\n",
    "\n",
    "### 4.4.2 发送服务请求："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['土地整治与土壤修复研究中心', '华南农业大学|东图']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['纯臻营养护发素', '产品信息/参数', '（45元/每公斤，100公斤起订', '每瓶22元，1000瓶起订）', '【品牌】：代加工方式/OEMODM', '【品名】：纯臻营养护发素', '【产品编号】：YM-X-3011', 'ODMOEM', '（净含量】：220ml', '【适用人群）：适合所有肤质', '［主要成分】：鲸蜡硬脂醇、燕麦B-葡聚', '糖、椰油酰胺内基甜菜碱、泛醒', '（成品包材）', '主要功能】：可紧致头发磷层，从而达到', '即时持久改善头发光泽的效果，给干燥的头', '发足够的滋养']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['Mairiedu|er|农', '*|Palais du LOUVRE', '公 LES ARTS DECORATIFS', '＊ Musée du LOUVRE', 'Theatre', 'du PALAIS-ROYAL L&']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['2', '证#', '', '##', '孔叫叫E2号动']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['合格证', '品名：纯棉单面背心套', '执行标准：FZ/T73025-2006', '安全类别：GB18401-2010', 'A类婴幼儿用品', '货号：B2390', 'DREA', '等级：一等品检验员：08', 'WOTHERAL', '成份：面料：100%棉', '小晶晶母婴', '品名：纯棉单面背心套', '上装：66/48', '零售价：47.50元', '下装：66/47']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['中国农业银行', 'AGRICULTURAL BANK OF CHINA', '美太网点办', '理务贵全融华务']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['Halten', 'Sie', 'Sie', 'was', 'versprechen', 'Und', 'geben', 'Sie noch', 'was dazu']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['上海斯格威铂尔受大酒店', '一打浦路15号', '绿洲仕格维花园公寓', '打浦路252935号']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['小学数学第八册第三单元测试题', '（小数乘法）', '姓名：', '班别：', '分数：', '计算题.(共38分）', '1.直接写出得数。（10分）', '0.8X25=', '0X4.23=', '0.57+0.43=', '2.4X0.2=', '0.02', 'X500=', '2.8X10=', '8.29X100=', '2.5X0.4=', '4.87-1.7=', '8.07', 'X1000=', '2.用坚式计算。（12分）', '2.97X3.8=', '7.05X0.84=']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['Paddle.jit.saveO', ': best accuracy.pdopt', ': inference.pdmodel', 'ich det mv3', '模型训练', 'i best accuracy.pdparams', '模型转换', 'opt优化模型', 'i inference.pdiparams', 'idb opt.nb', ': best accuracy.states']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['CreditCord', '中国工商银行', 'INDUSTRIL AD COMMERCIA BAHKSLUHIN', '持卡人存根', '商户名称&编号(MERCHANT NAME&CODE)', '工行浣纱支行积分兑换', '120214020408', '检索参考号(SYSTEMINOJ）', '终端号(TERMINAL)', '60128018', '001', '卡号（CARD NUMBER):', '622210512', 'S', '卡别（CARDTYPE)', '有效期(EXPIRY', '牡丹准货记卡', '交易日期DATE)', '交易时间(TIMEE)', '2012-10-23', '12:43:15', '批次号(BATCHNO.）', '流水号（TRACEHOJ', '000016', '积分兑奖', '信用卡积分：50000', '持卡人姓名（CARDHOLDERNAME）', 'MR.1', '持卡人签名', '(CARDHOLDER S', 'SIGNATURE:']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['1', 'EPPING', 'Twinned with', 'Eppingen，']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['订007778', 'PASS', '登机牌', 'BOARDING', '座位号', '序号', 'SERIALNO.', '舱位 CLASS', 'SEAT NO.', '航班 FLIGHT', '日期 DATE', 'W', '03DEC', '035', 'MU2379', 'GATE', '登机口', '始发地', 'FROM', '登机时间BDT', '自的地 TO', '福州', 'TAIYUAN', 'G11', 'FUZHOU', '身份识别ID NO.', '姓名NAME', 'ZHANGQIWET', '票号TKT NO', '张祺伟', '票价 FARE', 'ETKT7813699238489/1', '登机口于起飞前10分钟关闭 GATES CLOSE 10 MINUTES BEFORE DEPARTURE TIME']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['右', '天然の', '#', '味の占', '濃厚衣', '梦少久', '本勇5办', '味\\\\\\\\深', '燒', '深办の苏石', '苏扣子布', '5味の', '3-9', '警', '鲍の己品', '匕辛', '节办', '永书', '香', '梦之', '二の两石', '脂の秉龙', '力力', 'N', '乙龙の揚', '', '出来龙了', ':', '新鲜', '少手', '炊吉大了', '風味豊', '熟成L力', '二人办', '美味', '芳醇', '口の.', 'C', '二の石', '史方办套', '旬', '産地直送', '久七', '食人二', '秘の', '<<', '淹机个一卜', '>1一>一', '本場の', '朝探', '俊味吉', '七3寸子']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['7788.com', 'Z57A001950', '杭州东售', '2013年07月07日13:39开', '06车12B号', '二等座', '杭州东', 'G7512次', '上海虹桥', 'HangZhouDong', 'Shang HaiHongQiao', '￥73.00元', '限乘当日当次车', '余友红', '检票口16', '3623301993****0941', '9004-1300-5707-08A0-0195-0', '和谐号', 'C0400']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['Meters/bonwe', '洗涤说明', '淘X口Ne', '最高洗涤温度30°C', '常规程序', '不可漂白', '悬挂晾干', '熨斗底板最高温度110°C', '常规干洗', '注童事项：']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['3504811', '属瑞金医院', '标本号：OA', '支吉单（临床内分泌', '标本种类：血清', '标志提示：', '门诊号：E05535540', '门诊科别：门诊内分泌', '条码号：10080603139 临床诊断：', '申请医生：孙首悦', '检测日期：2010', '产', '龄：31', '检验备注：', '结果', '参考范围', '项目', '3.12', 'FT3', '2.62--6.49pmol/L', '15.40', 'FT4', '9.01--19.04pmol/L', '1.31', '0.35--4.94uIU/ml', 'STSH', '0.15', '<4.1110/ml', 'TGAB', '0.1', '25.0U/L', 'TRAb', '0.17', '<5.611U/ml', 'TPOAb', '0.1', '0.1--10.0pg/ml', '降钙素', '报告时间：10-08-0711:28', '打印时间：1', '采样时间：10-08-0611:23', '收到时间：10-08-0611:44', '核', '检验：李纪平', '对：保', '以上7项检验结果仅供临床医师参考']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['栏L。未来味元氨']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['代号', '项目', '结果', '参考值', '单位', '谷丙转氨酶', '25.6', '0--40', 'ALT', 'U/L', 'TBIL', '总胆红素', '11.2', '<20', 'UMO1/L', '直接胆红素', '3.3', '0--7', 'DBIL', 'UMOL/L', '间接胆红素', '7.9', 'IBIL', '1.5--15', 'UMOL/L', '总蛋白', '58.9V', '60--80', 'TP', 'S/L', '白蛋白', '35.1', '33--55', 'ALB', ':/L', '球蛋白', '23.8', '20--30', 'GLO', '8/L', '白球比', 'A/G', '1.5', '1.5--2.5', 'ALP', '可性磷酉酯', '93', '15--112', 'IU/L', '谷氨酰转肽酸', '<50', '14.3', 'GGT', 'U/L', '谷草转氨酶', 'AST', '16.3', '8--40', 'U/L', '乳酸脱氢酶', 'LDH', '167', '114--240', 'U/L', '腺甘脱氨酶', '12.6', '4--24', 'ADA', 'U/L']\"], 'tensors': []}\n",
      "{'err_no': 0, 'err_msg': '', 'key': ['res'], 'value': [\"['股股东的持股情况', '单位：股', '股东总数（户）', '75.103', '前十名股东持股情况', '持有有限售条', '质押或冻结情况', '股东名称', '期末持股数量', '比例', '件股份数量', '股东性质', '股份状态', '数量', '国有法人', 'HONG Leong Bank', '境外法人', '浩海产业投资基金管理', '240000000', '境内非国有法人', '0', '国有法人', '公司', '16000000', '16000000', '公司', '国有法人', '成都欣天颐投资有限责', '0', '国有法人', '上海东昌投资发展有限', '3.3220%', '冻结', '公司', '50.000.00境内非国有法人', '新华文轩出版传媒股份', '0', '80000.000', '国有法人', '四川新华发行集团有限', '71243800', '1.9723%', '公司', '国有法人', '71.154.900', '限责任公司', '国有法人']\"], 'tensors': []}\n",
      "==> total number of test imgs:  20\n"
     ]
    }
   ],
   "source": [
    "!python pipeline_http_client.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "进一步可以调整 config.yml 中的并发数，这里仅演示跑通效果，在这里默认都设置为1 \n",
    "\n",
    "```\n",
    "    det:\n",
    "        #并发数，is_thread_op=True时，为线程并发；否则为进程并发\n",
    "        concurrency: 1\n",
    "        ...\n",
    "    rec:\n",
    "        #并发数，is_thread_op=True时，为线程并发；否则为进程并发\n",
    "        concurrency: 1\n",
    "        ...\n",
    "```\n",
    "\n",
    "预测性能数据会被自动写入 `PipelineServingLogs/pipeline.tracer` 文件中。\n",
    "\n",
    "\n",
    "\n",
    "## 4.5 FAQ\n",
    "\n",
    "**Q1**： 发送请求后没有结果返回或者提示输出解码报错\n",
    "\n",
    "**A1**： 启动服务和发送请求时不要设置代理，可以在启动服务前和发送请求前关闭代理，关闭代理的命令是：\n",
    "```\n",
    "unset https_proxy\n",
    "unset http_proxy\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "# 5. 基于Paddle Lite的端侧推理实战\n",
    "\n",
    "随时移动互联网的普及，越来越多的手机、嵌入式设备被使用，同时考虑到数据安全性以及模型运行成本，越来越多的模型被直接运行在端侧设备中。\n",
    "\n",
    "Paddle Lite是飞桨轻量化推理引擎，为手机、IOT端提供高效推理能力，并广泛整合跨平台硬件，为端侧部署及应用落地问题提供轻量化的部署方案。\n",
    "\n",
    "本章介绍基于[Paddle Lite](https://github.com/PaddlePaddle/Paddle-Lite) 在移动端部署PaddleOCR超轻量中文检测、识别模型的步骤。\n",
    "\n",
    "\n",
    "下面给大家演示一下Android上运行PP-OCRv2系列模型的demo。\n",
    "\n",
    "[Android demo演示链接](https://paddleocr.bj.bcebos.com/presentation_demo/android_lite%20demo.mp4)\n",
    "\n",
    "\n",
    "由于在这里无法演示，在这里给大家介绍一下基于Paddle Lite开发PP-OCRv2系统运行程序的流程。\n",
    "\n",
    "如果希望实操，可以参考[PaddleOCR基于Paddle Lite的部署文档](https://github.com/PaddlePaddle/PaddleOCR/blob/dygraph/deploy/lite/readme.md)。\n",
    "\n",
    "## 5.1 准备环境\n",
    "\n",
    "这里需要同时准备交叉编译的环境以及Paddle Lite预测库，交叉编译环境用于生成可以在端侧设备上使用的可执行文件。推荐使用docker作为交叉编译环境。\n",
    "\n",
    "## 5.2 准备模型\n",
    "\n",
    "在使用Paddle Lite进行模型预测时，需要首先将推理模型转化为用于Paddle Lite预测的优化模型（后缀一般为`nb`），它采取了多种策略来自动优化原始的模型，其中包括量化、子图融合、混合调度、Kernel优选等方法。优化后的模型更轻量，速度更快。\n",
    "\n",
    "## 5.3 编译\n",
    "\n",
    "运行`make -j`执行编译，得到可执行文件, 第一次执行此命令会下载opencv等依赖库，等待下载完成之后再次运行`make -j`即可。\n",
    "\n",
    "## 5.4 上传至手机等移动端\n",
    "\n",
    "使用adb等工具，将可执行文件、模型文件、配置文件等传到手机等移动端上。\n",
    "\n",
    "## 5.5 运行\n",
    "\n",
    "在移动端中运行可执行文件即可得到结果，输出结果示例如下。\n",
    "\n",
    "<div align=\"center\">\n",
    "<img src=\"https://ai-studio-static-online.cdn.bcebos.com/c05a80380a6d483b81dd1be87f78beb4ec67659eabc7454686ea9588ea46c3ab\"  width = \"600\" />\n",
    "</div>\n",
    "<center>移动端输出结果</center>\n",
    "\n",
    "## 5.6 FAQ\n",
    "Q1：如果想更换模型怎么办，需要重新按照流程走一遍吗？\n",
    "\n",
    "A1：如果已经走通了上述步骤，更换模型只需要替换 .nb 模型文件即可，同时要注意更新字典\n",
    "\n",
    "Q2：换一个图测试怎么做？\n",
    "\n",
    "A2：替换debug下的.jpg测试图像为你想要测试的图像，adb push 到手机上即可\n",
    "\n",
    "Q3：如何封装到手机APP中？\n",
    "\n",
    "A3：此demo旨在提供能在手机上运行OCR的核心算法部分，PaddleOCR/deploy/android_demo是将这个demo封装到手机app的示例，供参考"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "# 6. 作业\n",
    "\n",
    "请参考[预测部署客观题](https://aistudio.baidu.com/aistudio/education/objective/28710)与[预测部署实战题](https://aistudio.baidu.com/aistudio/projectdetail/3297083)部分。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "py35-paddle1.2.0"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
