diff --git a/.github/workflows/gen_whl_to_pypi_rapid_layout.yml b/.github/workflows/gen_whl_to_pypi_rapid_layout.yml
deleted file mode 100644
index 62d9374..0000000
--- a/.github/workflows/gen_whl_to_pypi_rapid_layout.yml
+++ /dev/null
@@ -1,81 +0,0 @@
-name: Push rapidocr_layout to pypi
-
-on:
- push:
- branches: [ main ]
- paths:
- - 'python/rapid_structure/rapid_layout/**'
- - 'docs/doc_whl_rapid_layout.md'
- - 'python/rapid_structure/setup_layout.py'
- - '.github/workflows/gen_whl_to_pypi_rapid_layout.yml'
- - 'python/rapid_structure/tests/test_layout.py'
-
-env:
- RESOURCES_URL: https://github.com/RapidAI/RapidOCR/releases/download/v1.1.0/rapid_layout_models.zip
-
-jobs:
- UnitTesting:
- runs-on: ubuntu-latest
- steps:
- - name: Pull latest code
- uses: actions/checkout@v3
-
- - name: Set up Python 3.7
- uses: actions/setup-python@v4
- with:
- python-version: '3.7'
- architecture: 'x64'
-
- - name: Display Python version
- run: python -c "import sys; print(sys.version)"
-
- - name: Unit testings
- run: |
- wget $RESOURCES_URL
- ZIP_NAME=${RESOURCES_URL##*/}
- DIR_NAME=${ZIP_NAME%.*}
- unzip $DIR_NAME
- cp $DIR_NAME/*.onnx python/rapid_structure/rapid_layout/models/
- cd python/rapid_structure
- pip install -r requirements.txt
- pytest tests/test_layout.py
-
- GenerateWHL_PushPyPi:
- needs: UnitTesting
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v3
-
- - name: Set SSH Environment
- env:
- DEPLOY_KEYS: ${{ secrets.GEN_PYTHON_SDK }}
- run: |
- mkdir -p ~/.ssh/
- echo "$DEPLOY_KEYS" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- chmod 700 ~/.ssh && chmod 600 ~/.ssh/*
-
- - name: Run setup
- run: |
- cd python/rapid_structure
- pip install -r requirements.txt
- wget $RESOURCES_URL
- ZIP_NAME=${RESOURCES_URL##*/}
- DIR_NAME=${ZIP_NAME%.*}
- unzip $ZIP_NAME
- mv $DIR_NAME/*.onnx rapid_layout/models/
- python setup_layout.py bdist_wheel ${{ github.event.head_commit.message }}
-
- # - name: Publish distribution 📦 to Test PyPI
- # uses: pypa/gh-action-pypi-publish@v1.5.0
- # with:
- # password: ${{ secrets.TEST_PYPI_API_TOKEN }}
- # repository_url: https://test.pypi.org/legacy/
- # packages_dir: dist/
-
- - name: Publish distribution 📦 to PyPI
- uses: pypa/gh-action-pypi-publish@v1.5.0
- with:
- password: ${{ secrets.RAPIDOCR_OPENVINO }}
- packages_dir: python/rapid_structure/dist/
diff --git a/.github/workflows/gen_whl_to_pypi_rapid_orientation.yml b/.github/workflows/gen_whl_to_pypi_rapid_orientation.yml
deleted file mode 100644
index cf6993f..0000000
--- a/.github/workflows/gen_whl_to_pypi_rapid_orientation.yml
+++ /dev/null
@@ -1,86 +0,0 @@
-name: Push rapidocr_orientation to pypi
-
-on:
- push:
- branches: [ main ]
- paths:
- - 'python/rapid_structure/rapid_orientation/**'
- - 'docs/doc_whl_rapid_orientation.md'
- - 'python/rapid_structure/setup_orientation.py'
- - '.github/workflows/gen_whl_to_pypi_rapid_orientation.yml'
- - 'python/rapid_structure/tests/test_orientation.py'
-
-env:
- RESOURCES_URL: https://github.com/RapidAI/RapidOCR/releases/download/v1.1.0/rapid_orientation_models.zip
-
-jobs:
- UnitTesting:
- runs-on: ubuntu-latest
- steps:
- - name: Pull latest code
- uses: actions/checkout@v3
-
- - name: Set up Python 3.7
- uses: actions/setup-python@v4
- with:
- python-version: '3.7'
- architecture: 'x64'
-
- - name: Unit testings
- run: |
- wget $RESOURCES_URL
- ZIP_NAME=${RESOURCES_URL##*/}
- DIR_NAME=${ZIP_NAME%.*}
- unzip $ZIP_NAME
- rm python/rapid_structure/rapid_orientation/models/.gitkeep
- mv $DIR_NAME/*.onnx python/rapid_structure/rapid_orientation/models/
- cd python/rapid_structure
- pip install -r requirements.txt
- cd tests
- pytest test_orientation.py
-
- GenerateWHL_PushPyPi:
- needs: UnitTesting
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v3
-
- - name: Set up Python 3.7
- uses: actions/setup-python@v4
- with:
- python-version: '3.7'
- architecture: 'x64'
-
- - name: Set SSH Environment
- env:
- DEPLOY_KEYS: ${{ secrets.GEN_PYTHON_SDK }}
- run: |
- mkdir -p ~/.ssh/
- echo "$DEPLOY_KEYS" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- chmod 700 ~/.ssh && chmod 600 ~/.ssh/*
-
- - name: Run setup
- run: |
- cd python/rapid_structure
- pip install -r requirements.txt
- wget $RESOURCES_URL
- ZIP_NAME=${RESOURCES_URL##*/}
- DIR_NAME=${ZIP_NAME%.*}
- unzip $ZIP_NAME
- mv $DIR_NAME/*.onnx rapid_orientation/models/
- python setup_orientation.py bdist_wheel ${{ github.event.head_commit.message }}
-
- # - name: Publish distribution 📦 to Test PyPI
- # uses: pypa/gh-action-pypi-publish@v1.5.0
- # with:
- # password: ${{ secrets.TEST_PYPI_API_TOKEN }}
- # repository_url: https://test.pypi.org/legacy/
- # packages_dir: python/rapid_structure/dist/
-
- - name: Publish distribution 📦 to PyPI
- uses: pypa/gh-action-pypi-publish@v1.5.0
- with:
- password: ${{ secrets.RAPIDOCR_OPENVINO }}
- packages_dir: python/rapid_structure/dist/
diff --git a/.github/workflows/gen_whl_to_pypi_rapid_table.yml b/.github/workflows/gen_whl_to_pypi_rapid_table.yml
deleted file mode 100644
index 08e66fc..0000000
--- a/.github/workflows/gen_whl_to_pypi_rapid_table.yml
+++ /dev/null
@@ -1,88 +0,0 @@
-name: Push rapidocr_table to pypi
-
-on:
- push:
- branches: [ main ]
- paths:
- - 'python/rapid_structure/rapid_table/**'
- - 'docs/doc_whl_rapid_table.md'
- - 'python/rapid_structure/setup_table.py'
- - '.github/workflows/gen_whl_to_pypi_rapid_table.yml'
- - 'python/rapid_structure/tests/test_table.py'
-
-env:
- RESOURCES_URL: https://github.com/RapidAI/RapidOCR/releases/download/v1.1.0/rapid_table_models.zip
-
-jobs:
- UnitTesting:
- runs-on: ubuntu-latest
- steps:
- - name: Pull latest code
- uses: actions/checkout@v3
-
- - name: Set up Python 3.7
- uses: actions/setup-python@v4
- with:
- python-version: '3.7'
- architecture: 'x64'
-
- - name: Display Python version
- run: python -c "import sys; print(sys.version)"
-
- - name: Unit testings
- run: |
- wget $RESOURCES_URL
- ZIP_NAME=${RESOURCES_URL##*/}
- DIR_NAME=${ZIP_NAME%.*}
- unzip $DIR_NAME
- cp $DIR_NAME/*.onnx python/rapid_structure/rapid_table/models/
- cd python/rapid_structure
- pip install -r requirements.txt
- pip install rapidocr_onnxruntime
- pytest tests/test_table.py
-
- GenerateWHL_PushPyPi:
- needs: UnitTesting
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v3
-
- - name: Set up Python 3.7
- uses: actions/setup-python@v4
- with:
- python-version: '3.7'
- architecture: 'x64'
-
- - name: Set SSH Environment
- env:
- DEPLOY_KEYS: ${{ secrets.GEN_PYTHON_SDK }}
- run: |
- mkdir -p ~/.ssh/
- echo "$DEPLOY_KEYS" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- chmod 700 ~/.ssh && chmod 600 ~/.ssh/*
-
- - name: Run setup
- run: |
- cd python/rapid_structure
- pip install -r requirements.txt
- wget $RESOURCES_URL
- ZIP_NAME=${RESOURCES_URL##*/}
- DIR_NAME=${ZIP_NAME%.*}
- unzip $ZIP_NAME
- mv $DIR_NAME/en_ppstructure_mobile_v2_SLANet.onnx rapid_table/models/
- python setup_table.py bdist_wheel ${{ github.event.head_commit.message }}
-
- # - name: Publish distribution 📦 to Test PyPI
- # uses: pypa/gh-action-pypi-publish@v1.5.0
- # with:
- # password: ${{ secrets.TEST_PYPI_API_TOKEN }}
- # repository_url: https://test.pypi.org/legacy/
- # packages_dir: dist/
-
- - name: Publish distribution 📦 to PyPI
- uses: pypa/gh-action-pypi-publish@v1.5.0
- with:
- password: ${{ secrets.RAPIDOCR_OPENVINO }}
- packages_dir: python/rapid_structure/dist/
diff --git a/README.md b/README.md
index 81909ca..7564b44 100755
--- a/README.md
+++ b/README.md
@@ -81,13 +81,14 @@
- [网页版OCR](https://github.com/RapidAI/RapidOCR/blob/main/ocrweb/README.md)
- [Nuitka打包rapdocr_web](https://github.com/RapidAI/RapidOCR/wiki/Nuitka%E6%89%93%E5%8C%85rapidocr_web%E6%93%8D%E4%BD%9C%E6%96%87%E6%A1%A3)
- [多语言网页版OCR](https://github.com/RapidAI/RapidOCR/blob/main/ocrweb_multi/README.md)
-- [版面结构化](https://github.com/RapidAI/RapidOCR/blob/main/python/rapid_structure/README.md)
- - [含文本的图像方向分类](https://github.com/RapidAI/RapidOCR/blob/main/python/rapid_structure/docs/README_Orientation.md)
- - [版面分析](https://github.com/RapidAI/RapidOCR/blob/main/python/rapid_structure/docs/README_Layout.md)
- - [表格还原](https://github.com/RapidAI/RapidOCR/blob/main/python/rapid_structure/docs/README_Table.md)
+- [版面结构化-RapidStructure](https://github.com/RapidAI/RapidStructure)
+ - [含文本的图像方向分类](https://github.com/RapidAI/RapidStructure/blob/main/docs/README_Orientation.md)
+ - [版面分析](https://github.com/RapidAI/RapidStructure/blob/main/docs/README_Layout.md)
+ - [表格还原](https://github.com/RapidAI/RapidStructure/blob/main/docs/README_Table.md)
- 衍生项目
- [RapidOCR HTTP服务/win32程序/易语言编写](https://github.com/Physton/RapidOCRServer)
- [垂直项目](https://github.com/RapidAI/RapidOCR/blob/main/docs/related_projects.md)
+ - [RapidOCRPDF](https://github.com/RapidAI/RapidOCRPDF):解析PDF文件
- [RapidVideOCR](https://github.com/SWHL/RapidVideOCR):基于RapidOCR,提取视频中的硬字幕
- [LGPMA_Infer](https://github.com/SWHL/LGPMA_Infer): 表格结构还原 | [博客解读论文和源码](http://t.csdn.cn/QNN3S)
- [文档图像矫正-PaperEdge](https://github.com/cvlab-stonybrook/PaperEdge) | [Demo](https://huggingface.co/spaces/SWHL/PaperEdgeDemo)
diff --git a/docs/README_en.md b/docs/README_en.md
index 083ddb8..eee78b9 100644
--- a/docs/README_en.md
+++ b/docs/README_en.md
@@ -73,13 +73,14 @@
- [Web OCR](https://github.com/RapidAI/RapidOCR/blob/main/ocrweb/README.md)
- [Nuitka package rapdocr_web](https://github.com/RapidAI/RapidOCR/wiki/Nuitka%E6%89%93%E5%8C%85rapidocr_web%E6%93%8D%E4%BD%9C%E6%96%87%E6%A1%A3)
- [Multi Web OCR](https://github.com/RapidAI/RapidOCR/blob/main/ocrweb_multi/README.md)
-- [Structure](https://github.com/RapidAI/RapidOCR/blob/main/python/rapid_structure/README.md)
- - [orientation](https://github.com/RapidAI/RapidOCR/blob/main/python/rapid_structure/docs/README_Orientation.md)
- - [layout](https://github.com/RapidAI/RapidOCR/blob/main/python/rapid_structure/docs/README_Layout.md)
- - [table recovery](https://github.com/RapidAI/RapidOCR/blob/main/python/rapid_structure/docs/README_Table.md)
+- [RapidStructure](https://github.com/RapidAI/RapidStructure)
+ - [orientation](https://github.com/RapidAI/RapidStructure/blob/main/docs/README_Orientation.md)
+ - [layout](https://github.com/RapidAI/RapidStructure/blob/main/docs/README_Layout.md)
+ - [table recovery](https://github.com/RapidAI/RapidStructure/blob/main/docs/README_Table.md)
- Derivatives
- [RapidOCR HTTP service/win32 program/easy language writing](https://github.com/Physton/RapidOCRServer)
- [Related projects](https://github.com/RapidAI/RapidOCR/blob/main/docs/related_projects.md)
+ - [RapidOCRPDF](https://github.com/RapidAI/RapidOCRPDF):extract PDF content.
- [RapidVideOCR](https://github.com/SWHL/RapidVideOCR): Extract hard subtitles in videos based on RapidOCR
- [LGPMA_Infer](https://github.com/SWHL/LGPMA_Infer): table structure restoration | [blog interpretation papers and source code](http://t.csdn.cn/QNN3S)
- [Document Unwarping-PaperEdge](https://github.com/cvlab-stonybrook/PaperEdge) | [Demo](https://huggingface.co/spaces/SWHL/PaperEdgeDemo)
diff --git a/docs/doc_whl_rapid_layout.md b/docs/doc_whl_rapid_layout.md
deleted file mode 100644
index 29f40cf..0000000
--- a/docs/doc_whl_rapid_layout.md
+++ /dev/null
@@ -1,60 +0,0 @@
-## rapid-layout Package
-
-
-
-
-
-
-### 1. Install package by pypi.
-```bash
-$ pip install rapid-layout
-```
-
-### 2. Run by script.
-- RapidLayout has the default `model_path` value, you can set the different value of `model_path` to use different models, e.g. `layout_engine = RapidLayout(model_path='layout_publaynet.onnx')`
-- See details, for [README_Layout](https://github.com/RapidAI/RapidOCR/blob/f133ff008a1c60edd6e0ed882da83873aa7b113a/python/rapid_structure/docs/README_Layout.md) .
-- 📌 `layout.png` source: [link](https://github.com/RapidAI/RapidOCR/blob/f133ff008a1c60edd6e0ed882da83873aa7b113a/python/rapid_structure/test_images/layout.png)
-
-```python
-import cv2
-from rapid_layout import RapidLayout
-
-layout_engine = RapidLayout()
-
-img = cv2.imread('layout.png')
-
-layout_res, elapse = layout_engine(img)
-print(layout_res)
-```
-
-### 3. Run by command line.
-- Usage:
- ```bash
- $ rapid_layout -h
- usage: rapid_layout [-h] [-v] -img IMG_PATH [-m MODEL_PATH]
-
- optional arguments:
- -h, --help show this help message and exit
- -v, --vis Wheter to visualize the layout results.
- -img IMG_PATH, --img_path IMG_PATH
- Path to image for layout.
- -m MODEL_PATH, --model_path MODEL_PATH
- The model path used for inference.
- ```
-- Example:
- ```bash
- $ rapid_layout -v -img layout.png
- ```
-
-### 4. Result.
-- Return value.
- ```python
- [
- {'bbox': array([321.4160495, 91.53214898, 562.06141263, 199.85522603]), 'label': 'text'},
- {'bbox': array([58.67292211, 107.29000663, 300.25448676, 199.68142]), 'label': 'table_caption'}
- ]
- ```
-- Visualize result.
-
-

-
diff --git a/docs/doc_whl_rapid_orientation.md b/docs/doc_whl_rapid_orientation.md
deleted file mode 100644
index dd751ed..0000000
--- a/docs/doc_whl_rapid_orientation.md
+++ /dev/null
@@ -1,51 +0,0 @@
-## rapid-orientation Package
-
-
-
-
-
-
-### 1. Install package by pypi.
-```bash
-$ pip install rapid-orientation
-```
-
-### 2. Run by script.
-- RapidOrientation has the default `model_path` value, you can set the different value of `model_path` to use different models, e.g. `orientation_engine = RapidOrientation(model_path='rapid_orientation.onnx')`
-- See details, for [README_Layout](https://github.com/RapidAI/RapidOCR/blob/f133ff008a1c60edd6e0ed882da83873aa7b113a/python/rapid_structure/docs/README_Layout.md) .
-- 📌 `layout.png` source: [link](https://github.com/RapidAI/RapidOCR/blob/f133ff008a1c60edd6e0ed882da83873aa7b113a/python/rapid_structure/test_images/layout.png)
-
-```python
-import cv2
-from rapid_orientation import RapidOrientation
-
-orientation_engine = RapidOrientation()
-
-img = cv2.imread('test_images/layout.png')
-
-orientation_res, elapse = orientation_engine(img)
-print(orientation_res)
-```
-
-### 3. Run by command line.
-- Usage:
- ```bash
- $ rapid_orientation -h
- usage: rapid_orientation [-h] -img IMG_PATH [-m MODEL_PATH]
-
- optional arguments:
- -h, --help show this help message and exit
- -img IMG_PATH, --img_path IMG_PATH
- Path to image for layout.
- -m MODEL_PATH, --model_path MODEL_PATH
- The model path used for inference
- ```
-- Example:
- ```bash
- $ rapid_orientation -img layout.png
- ```
-
-### 4. Result.
-```python
-# Return str, four types::0 | 90 | 180 | 270
-```
\ No newline at end of file
diff --git a/docs/doc_whl_rapid_table.md b/docs/doc_whl_rapid_table.md
deleted file mode 100644
index 6534b24..0000000
--- a/docs/doc_whl_rapid_table.md
+++ /dev/null
@@ -1,41 +0,0 @@
-## rapid-table Package
-
-
-
-
-
-### 1. Install package by pypi.
-```bash
-$ pip install rapid-table
-```
-
-### 2. Run by script.
-- RapidTable has the default `model_path` value, you can set the different value of `model_path` to use different models, e.g. `table_engine = RapidTable(model_path='ch_ppstructure_mobile_v2_SLANet.onnx')`
-- See details, for [README_Table](https://github.com/RapidAI/RapidOCR/blob/a87133a6fc3b8ee696e246028e529f7b2319d138/python/rapid_structure/docs/README_Table.md) .
-- 📌 `table.jpg` source: [link](https://github.com/RapidAI/RapidOCR/blob/a87133a6fc3b8ee696e246028e529f7b2319d138/python/rapid_structure/test_images/table.jpg)
-
-```python
-import cv2
-from rapid_table import RapidTable
-
-table_engine = RapidTable()
-
-img = cv2.imread('table.jpg')
-table_html_str, _ = table_engine(img)
-print(table_html_str)
-```
-
-### 3. Run by command line.
-```bash
-$ rapid_table -v -img table.jpg
-```
-
-### 4. Result.
-- Return value.
- ```html
- | Methods | | | | FPS |
| SegLink [26] | 70.0 | 86d> | 77.0 | 8.9 |
| PixelLink [4] | 73.2 | 83.0 | 77.8 | |
| TextSnake [18] | 73.9 | 83.2 | 78.3 | 1.1 |
| TextField [37] | 75.9 | 87.4 | 81.3 | 5.2 |
| MSR[38] | 76.7 | 87.87.4 | 81.7 | |
| FTSN [3] | 77.1 | 87.6 | 82.0 | |
| LSE[30] | 81.7 | 84.2 | 82.9 | <>
| CRAFT [2] | 78.2 | 88.2 | 82.9 | 8.6 |
| MCN[16] | 79 | 88 | 83 | |
| ATRR>[35] | 82.1 | 85.2 | 83.6 | |
| PAN [34] | 83.8 | 84.4 | 84.1 | 30.2 |
| DB[12] | 79.2 | 91.5 | 84.9 | 32.0 |
| DRRG[41] | 82.30 | 88.05 | 85.08 | |
| Ours (SynText) | 80.68 | 85| 82.97 | 12.68 | |
| Ours (MLT-17) | 84.54 | 86.62 | 85.57 | 12.31 |
- ```
-- Visualize result.
-
-
| Methods | | | | FPS |
| SegLink [26] | 70.0 | 86d> | 77.0 | 8.9 |
| PixelLink [4] | 73.2 | 83.0 | 77.8 | |
| TextSnake [18] | 73.9 | 83.2 | 78.3 | 1.1 |
| TextField [37] | 75.9 | 87.4 | 81.3 | 5.2 |
| MSR[38] | 76.7 | 87.87.4 | 81.7 | |
| FTSN [3] | 77.1 | 87.6 | 82.0 | |
| LSE[30] | 81.7 | 84.2 | 82.9 | <>
| CRAFT [2] | 78.2 | 88.2 | 82.9 | 8.6 |
| MCN[16] | 79 | 88 | 83 | |
| ATRR>[35] | 82.1 | 85.2 | 83.6 | |
| PAN [34] | 83.8 | 84.4 | 84.1 | 30.2 |
| DB[12] | 79.2 | 91.5 | 84.9 | 32.0 |
| DRRG[41] | 82.30 | 88.05 | 85.08 | |
| Ours (SynText) | 80.68 | 85| 82.97 | 12.68 | |
| Ours (MLT-17) | 84.54 | 86.62 | 85.57 | 12.31 |
-
diff --git a/python/rapid_structure/README.md b/python/rapid_structure/README.md
deleted file mode 100644
index 0db38a2..0000000
--- a/python/rapid_structure/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-## Rapid Structure
-- 该部分的功能主要针对文档类图像,包括文档图像分类、版面分析和表格识别。
-
-### [版面分析](https://github.com/RapidAI/RapidOCR/blob/main/python/rapid_structure/docs/README_Layout.md)
-
-### [表格识别](https://github.com/RapidAI/RapidOCR/blob/main/python/rapid_structure/docs/README_Table.md)
-
-### [文档方向分类](https://github.com/RapidAI/RapidOCR/blob/main/python/rapid_structure/docs/README_Orientation.md)
-
-### 整体结构
-```mermaid
-flowchart LR
- A[/文档图像/] --> B(文档方向分类 rapid_orientation) --> C(版面分析 rapid_layout) & D(表格识别 rapid_table) --> E(OCR识别 rapidocr_onnxruntime)
- E --> F(结构化输出)
-```
\ No newline at end of file
diff --git a/python/rapid_structure/demo.py b/python/rapid_structure/demo.py
deleted file mode 100644
index 4745930..0000000
--- a/python/rapid_structure/demo.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-import copy
-from pathlib import Path
-
-import cv2
-import numpy as np
-
-from rapid_layout import RapidLayout
-from rapid_orientation import RapidOrientation
-from rapid_table import RapidTable
-
-
-def vis_layout(img: np.ndarray, layout_res: list) -> None:
- tmp_img = copy.deepcopy(img)
- for v in layout_res:
- bbox = np.round(v['bbox']).astype(np.int32)
- label = v['label']
-
- start_point = (bbox[0], bbox[1])
- end_point = (bbox[2], bbox[3])
-
- cv2.rectangle(tmp_img, start_point, end_point, (0, 255, 0), 2)
- cv2.putText(tmp_img, label, start_point,
- cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 2)
-
- draw_img_save = Path("./inference_results/")
- if not draw_img_save.exists():
- draw_img_save.mkdir(parents=True, exist_ok=True)
-
- image_save = str(draw_img_save / 'layout_result.jpg')
- cv2.imwrite(image_save, tmp_img)
- print(f'The infer result has saved in {image_save}')
-
-
-def vis_table(table_res):
- style_res = ''''''
- prefix_table, suffix_table = table_res.split('')
- new_table_res = f'{prefix_table}{style_res}{suffix_table}'
-
- draw_img_save = Path("./inference_results/")
- if not draw_img_save.exists():
- draw_img_save.mkdir(parents=True, exist_ok=True)
-
- html_path = str(draw_img_save / 'table_result.html')
- with open(html_path, 'w', encoding='utf-8') as f:
- f.write(new_table_res)
- print(f'The infer result has saved in {html_path}')
-
-
-def demo_layout():
- layout_engine = RapidLayout()
-
- img = cv2.imread('test_images/layout.png')
-
- layout_res, _ = layout_engine(img)
-
- vis_layout(img, layout_res)
- print(layout_res)
-
-
-def demo_table():
- table_engine = RapidTable()
- img = cv2.imread('test_images/table.jpg')
- table_html_str, _ = table_engine(img)
-
- vis_table(table_html_str)
- print(table_html_str)
-
-
-def demo_orientation():
- orientation_engine = RapidOrientation()
- img = cv2.imread('tests/test_files/img_rot180_demo.jpg')
- cls_result, _ = orientation_engine(img)
- print(cls_result)
-
-
-if __name__ == '__main__':
- demo_layout()
- # demo_table()
- # demo_orientation()
diff --git a/python/rapid_structure/docs/README_Layout.md b/python/rapid_structure/docs/README_Layout.md
deleted file mode 100644
index 7c83b37..0000000
--- a/python/rapid_structure/docs/README_Layout.md
+++ /dev/null
@@ -1,73 +0,0 @@
-## Rapid Layout
-
-
-
-
-
-
-
-#### 简介和说明
-- 该部分主要是做文档类图像的版面分析。模型来源:[PaddleOCR 版面分析](https://github.com/PaddlePaddle/PaddleOCR/blob/133d67f27dc8a241d6b2e30a9f047a0fb75bebbe/ppstructure/layout/README_ch.md)
-- 具体来说,就是分析给定的文档类别图像(论文截图等),定位其中类别和位置,如标题、段落、表格和图片等各个部分。
-- 目前支持三种类别的版面分析模型:中文、英文和表格版面分析模型,具体可参见下面表格:
-
- | 模型类型 | 模型名称 | 模型大小 | 支持种类 |
- |:---:|:---:|:---:|:---:|
- | 表格 | `layout_table.onnx` | 7.06M | `table` |
- | 英文 | `layout_publaynet.onnx` | 7.06M | `text title list table figure` |
- | 中文 | `layout_cdla.onnx` | 7.07M | `text title figure figure_caption table table_caption`
`header footer reference equation` |
-- 模型下载地址为:[百度网盘](https://pan.baidu.com/s/1PI9fksW6F6kQfJhwUkewWg?pwd=p29g) | [Google Drive](https://drive.google.com/drive/folders/1DAPWSN2zGQ-ED_Pz7RaJGTjfkN2-Mvsf?usp=sharing)
-
-#### 使用方式
-1. pip安装
- - 由于模型较小,预先将中文版面分析模型(`layout_cdla.onnx`)打包进了whl包内,如果做中文版面分析,可直接安装使用
- ```bash
- $ pip install rapid-layout
- ```
-2. python脚本运行
- ```python
- import cv2
- from rapid_layout import RapidLayout
-
- # RapidLayout类提供model_path参数,可以自行指定上述3个模型,默认是layout_cdla.onnx
- # layout_engine = RapidLayout(model_path='layout_publaynet.onnx')
- layout_engine = RapidLayout()
-
- img = cv2.imread('test_images/layout.png')
-
- layout_res, elapse = layout_engine(img)
- ```
-
-3. 终端运行
- - 用法:
- ```bash
- $ rapid_layout -h
- usage: rapid_layout [-h] [-v] -img IMG_PATH [-m MODEL_PATH]
-
- optional arguments:
- -h, --help show this help message and exit
- -v, --vis Wheter to visualize the layout results.
- -img IMG_PATH, --img_path IMG_PATH
- Path to image for layout.
- -m MODEL_PATH, --model_path MODEL_PATH
- The model path used for inference.
- ```
- - 示例:
- ```bash
- $ rapid_layout -v -img test_images/layout.png
- ```
-
-4. 结果
- - 返回结果
- ```python
- # bbox: [左上角x0,左上角y0, 右下角x0, 右上角x1]
- # label: 类别
- [
- {'bbox': array([321.4160495, 91.53214898, 562.06141263, 199.85522603]), 'label': 'text'},
- {'bbox': array([58.67292211, 107.29000663, 300.25448676, 199.68142]), 'label': 'table_caption'}
- ]
- ```
- - 可视化结果
-
-

-
diff --git a/python/rapid_structure/docs/README_Orientation.md b/python/rapid_structure/docs/README_Orientation.md
deleted file mode 100644
index 19f2ac2..0000000
--- a/python/rapid_structure/docs/README_Orientation.md
+++ /dev/null
@@ -1,56 +0,0 @@
-## Rapid Orientation
-
-
-
-
-
-
-
-#### 简介和说明
-- 该部分主要是做含文字图像方向分类模型。模型来源:[PaddleClas 含文字图像方向分类模型](https://github.com/PaddlePaddle/PaddleClas/blob/177e4be74639c0960efeae2c5166d3226c9a02eb/docs/zh_CN/models/PULC/PULC_text_image_orientation.md)
-
- | 模型类型 | 模型名称 | 模型大小 | 支持种类 |
- |:---:|:---:|:---:|:---:|
- | 四方向分类 | `rapid_orientation.onnx` | 6.5M | `0 90 180 270`|
-
-#### 使用方式
-1. pip安装
- - 由于模型较小,已经将分类模型(`rapid_orientation.onnx`)打包进了whl包内:
- ```bash
- $ pip install rapid-orientation
- ```
-2. python脚本运行
- ```python
- import cv2
- from rapid_orientation import RapidOrientation
-
- orientation_engine = RapidOrientation()
-
- img = cv2.imread('test_images/layout.png')
-
- orientation_res, elapse = orientation_engine(img)
- print(orientation_res)
- ```
-
-3. 终端运行
- - 用法:
- ```bash
- $ rapid_orientation -h
- usage: rapid_orientation [-h] -img IMG_PATH [-m MODEL_PATH]
-
- optional arguments:
- -h, --help show this help message and exit
- -img IMG_PATH, --img_path IMG_PATH
- Path to image for layout.
- -m MODEL_PATH, --model_path MODEL_PATH
- The model path used for inference.
- ```
- - 示例:
- ```bash
- $ rapid_orientation -img test_images/layout.png
- ```
-
-4. 结果
- ```python
- # 返回结果为str类型,有四类:0 | 90 | 180 | 270
- ```
diff --git a/python/rapid_structure/docs/README_Table.md b/python/rapid_structure/docs/README_Table.md
deleted file mode 100644
index 08610bd..0000000
--- a/python/rapid_structure/docs/README_Table.md
+++ /dev/null
@@ -1,66 +0,0 @@
-## Rapid Table
-
-
-
-
-
-
-
-#### 简介和说明
-- 该部分主要是做文档类图像的表格结构还原。模型来源:[PaddleOCR 表格识别](https://github.com/PaddlePaddle/PaddleOCR/blob/133d67f27dc8a241d6b2e30a9f047a0fb75bebbe/ppstructure/table/README_ch.md)
-- 具体来说,就是分析给定的表格图像,将表格还原为对应的html格式。
-- 目前支持两种类别的表格识别模型:中文和英文表格识别模型,具体可参见下面表格:
-
- | 模型类型 | 模型名称 | 模型大小 |
- |:---:|:---:|:---:|
- | 英文 | `en_ppstructure_mobile_v2_SLANet.onnx` | 7.3M |
- | 中文 | `ch_ppstructure_mobile_v2_SLANet.onnx` | 7.4M |
-- 模型下载地址为:[百度网盘](https://pan.baidu.com/s/1PI9fksW6F6kQfJhwUkewWg?pwd=p29g) | [Google Drive](https://drive.google.com/drive/folders/1DAPWSN2zGQ-ED_Pz7RaJGTjfkN2-Mvsf?usp=sharing)
-
-#### 使用方式
-1. pip安装
- - 由于模型较小,预先将英文表格识别模型(`en_ppstructure_mobile_v2_SLANet.onnx`)打包进了whl包内,如果做英文表格识别,可直接安装使用
- ```bash
- $ pip install rapid-table
- ```
-2. python脚本运行
- ```python
- import cv2
- from rapid_table import RapidTable
-
- # RapidTable类提供model_path参数,可以自行指定上述2个模型,默认是en_ppstructure_mobile_v2_SLANet.onnx
- # table_engine = RapidTable(model_path='ch_ppstructure_mobile_v2_SLANet.onnx')
- table_engine = RapidTable()
-
- img = cv2.imread('test_images/table.jpg')
- table_html_str, _ = table_engine(img)
- print(table_html_str)
- ```
-3. 终端运行
- - 用法:
- ```bash
- $ rapid_table -h
- usage: rapid_table [-h] [-v] -img IMG_PATH [-m MODEL_PATH]
-
- optional arguments:
- -h, --help show this help message and exit
- -v, --vis Wheter to visualize the layout results.
- -img IMG_PATH, --img_path IMG_PATH
- Path to image for layout.
- -m MODEL_PATH, --model_path MODEL_PATH
- The model path used for inference.
- ```
- - 示例:
- ```bash
- $ rapid_table -v -img test_images/table.jpg
- ```
-
-4. 结果
- - 返回结果
- ```html
- | Methods | | | | FPS |
| SegLink [26] | 70.0 | 86d> | 77.0 | 8.9 |
| PixelLink [4] | 73.2 | 83.0 | 77.8 | |
| TextSnake [18] | 73.9 | 83.2 | 78.3 | 1.1 |
| TextField [37] | 75.9 | 87.4 | 81.3 | 5.2 |
| MSR[38] | 76.7 | 87.87.4 | 81.7 | |
| FTSN [3] | 77.1 | 87.6 | 82.0 | |
| LSE[30] | 81.7 | 84.2 | 82.9 | <>
| CRAFT [2] | 78.2 | 88.2 | 82.9 | 8.6 |
| MCN[16] | 79 | 88 | 83 | |
| ATRR>[35] | 82.1 | 85.2 | 83.6 | |
| PAN [34] | 83.8 | 84.4 | 84.1 | 30.2 |
| DB[12] | 79.2 | 91.5 | 84.9 | 32.0 |
| DRRG[41] | 82.30 | 88.05 | 85.08 | |
| Ours (SynText) | 80.68 | 85| 82.97 | 12.68 | |
| Ours (MLT-17) | 84.54 | 86.62 | 85.57 | 12.31 |
- ```
- - 可视化结果
-
-
| Methods | | | | FPS |
| SegLink [26] | 70.0 | 86d> | 77.0 | 8.9 |
| PixelLink [4] | 73.2 | 83.0 | 77.8 | |
| TextSnake [18] | 73.9 | 83.2 | 78.3 | 1.1 |
| TextField [37] | 75.9 | 87.4 | 81.3 | 5.2 |
| MSR[38] | 76.7 | 87.87.4 | 81.7 | |
| FTSN [3] | 77.1 | 87.6 | 82.0 | |
| LSE[30] | 81.7 | 84.2 | 82.9 | <>
| CRAFT [2] | 78.2 | 88.2 | 82.9 | 8.6 |
| MCN[16] | 79 | 88 | 83 | |
| ATRR>[35] | 82.1 | 85.2 | 83.6 | |
| PAN [34] | 83.8 | 84.4 | 84.1 | 30.2 |
| DB[12] | 79.2 | 91.5 | 84.9 | 32.0 |
| DRRG[41] | 82.30 | 88.05 | 85.08 | |
| Ours (SynText) | 80.68 | 85| 82.97 | 12.68 | |
| Ours (MLT-17) | 84.54 | 86.62 | 85.57 | 12.31 |
-
\ No newline at end of file
diff --git a/python/rapid_structure/rapid_layout/__init__.py b/python/rapid_structure/rapid_layout/__init__.py
deleted file mode 100644
index 79e4a04..0000000
--- a/python/rapid_structure/rapid_layout/__init__.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-from .rapid_layout import RapidLayout
diff --git a/python/rapid_structure/rapid_layout/config.yaml b/python/rapid_structure/rapid_layout/config.yaml
deleted file mode 100644
index 33a85d2..0000000
--- a/python/rapid_structure/rapid_layout/config.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-model_path: models/layout_cdla.onnx
-
-use_cuda: false
-CUDAExecutionProvider:
- device_id: 0
- arena_extend_strategy: kNextPowerOfTwo
- cudnn_conv_algo_search: EXHAUSTIVE
- do_copy_in_default_stream: true
-
-pre_process:
- Resize:
- size: [800, 608]
- NormalizeImage:
- std: [0.229, 0.224, 0.225]
- mean: [0.485, 0.456, 0.406]
- scale: 1./255.
- order: hwc
- ToCHWImage:
- KeepKeys:
- keep_keys: ['image']
-
-post_process:
- score_threshold: 0.5
- nms_threshold: 0.5
\ No newline at end of file
diff --git a/python/rapid_structure/rapid_layout/models/.gitkeep b/python/rapid_structure/rapid_layout/models/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/python/rapid_structure/rapid_layout/rapid_layout.py b/python/rapid_structure/rapid_layout/rapid_layout.py
deleted file mode 100644
index 178c015..0000000
--- a/python/rapid_structure/rapid_layout/rapid_layout.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-import argparse
-import time
-from pathlib import Path
-
-import cv2
-import numpy as np
-
-from .utils import (OrtInferSession, PicoDetPostProcess, create_operators,
- read_yaml, transform, vis_layout)
-
-root_dir = Path(__file__).resolve().parent
-
-
-class RapidLayout():
- def __init__(self,
- model_path: str = None):
- config_path = str(root_dir / 'config.yaml')
- config = read_yaml(config_path)
- if model_path is None:
- model_path = str(root_dir / 'models' / 'layout_cdla.onnx')
- config['model_path'] = model_path
-
- self.session = OrtInferSession(config)
- labels = self.session.get_metadata()['character'].splitlines()
-
- self.preprocess_op = create_operators(config['pre_process'])
- self.postprocess_op = PicoDetPostProcess(labels,
- **config['post_process'])
-
- def __call__(self, img):
- ori_im = img.copy()
- data = {'image': img}
- data = transform(data, self.preprocess_op)
- img = data[0]
-
- if img is None:
- return None, 0
-
- img = np.expand_dims(img, axis=0)
- img = img.copy()
-
- preds, elapse = 0, 1
- starttime = time.time()
-
- preds = self.session(img)
-
- score_list, boxes_list = [], []
- num_outs = int(len(preds) / 2)
- for out_idx in range(num_outs):
- score_list.append(preds[out_idx])
- boxes_list.append(preds[out_idx + num_outs])
- preds = dict(boxes=score_list, boxes_num=boxes_list)
- post_preds = self.postprocess_op(ori_im, img, preds)
- elapse = time.time() - starttime
- return post_preds, elapse
-
-
-def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('-v', '--vis', action='store_true',
- help='Wheter to visualize the layout results.')
- parser.add_argument('-img', '--img_path', type=str, required=True,
- help='Path to image for layout.')
- parser.add_argument('-m', '--model_path', type=str,
- default=str(root_dir / 'models' / 'layout_cdla.onnx'),
- help='The model path used for inference.')
- args = parser.parse_args()
-
- layout_engine = RapidLayout(args.model_path)
-
- img = cv2.imread(args.img_path)
- layout_res, elapse = layout_engine(img)
- print(layout_res)
-
- if args.vis:
- img_path = Path(args.img_path)
- save_path = img_path.resolve().parent / f'vis_{img_path.name}'
- vis_layout(img, layout_res, str(save_path))
-
-
-if __name__ == '__main__':
- main()
diff --git a/python/rapid_structure/rapid_layout/utils.py b/python/rapid_structure/rapid_layout/utils.py
deleted file mode 100644
index 70f3b2f..0000000
--- a/python/rapid_structure/rapid_layout/utils.py
+++ /dev/null
@@ -1,443 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-import copy
-import warnings
-from pathlib import Path
-
-import yaml
-import cv2
-import numpy as np
-from onnxruntime import (get_available_providers, get_device,
- SessionOptions, InferenceSession,
- GraphOptimizationLevel)
-
-
-class OrtInferSession():
- def __init__(self, config):
- sess_opt = SessionOptions()
- sess_opt.log_severity_level = 4
- sess_opt.enable_cpu_mem_arena = False
- sess_opt.graph_optimization_level = GraphOptimizationLevel.ORT_ENABLE_ALL
-
- cuda_ep = 'CUDAExecutionProvider'
- cpu_ep = 'CPUExecutionProvider'
- cpu_provider_options = {"arena_extend_strategy": "kSameAsRequested",}
-
- EP_list = []
- if config['use_cuda'] and get_device() == 'GPU' \
- and cuda_ep in get_available_providers():
- EP_list = [(cuda_ep, config[cuda_ep])]
- EP_list.append((cpu_ep, cpu_provider_options))
-
- self._verify_model(config['model_path'])
- self.session = InferenceSession(config['model_path'],
- sess_options=sess_opt,
- providers=EP_list)
-
- if config['use_cuda'] and cuda_ep not in self.session.get_providers():
- warnings.warn(f'{cuda_ep} is not avaiable for current env, the inference part is automatically shifted to be executed under {cpu_ep}.\n'
- 'Please ensure the installed onnxruntime-gpu version matches your cuda and cudnn version, '
- 'you can check their relations from the offical web site: '
- 'https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html',
- RuntimeWarning)
-
- def __call__(self, input_content: np.ndarray) -> np.ndarray:
- input_dict = dict(zip(self.get_input_names(), [input_content]))
- try:
- return self.session.run(self.get_output_names(), input_dict)
- except Exception as e:
- raise ONNXRuntimeError('ONNXRuntime inferece failed.') from e
-
- def get_input_names(self, ):
- return [v.name for v in self.session.get_inputs()]
-
- def get_output_names(self,):
- return [v.name for v in self.session.get_outputs()]
-
- def get_metadata(self):
- meta_dict = self.session.get_modelmeta().custom_metadata_map
- return meta_dict
-
- @staticmethod
- def _verify_model(model_path):
- model_path = Path(model_path)
- if not model_path.exists():
- raise FileNotFoundError(f'{model_path} does not exists.')
- if not model_path.is_file():
- raise FileExistsError(f'{model_path} is not a file.')
-
-
-class ONNXRuntimeError(Exception):
- pass
-
-
-def transform(data, ops=None):
- """ transform """
- if ops is None:
- ops = []
-
- for op in ops:
- data = op(data)
- if data is None:
- return None
- return data
-
-
-def create_operators(op_param_dict):
- ops = []
- for op_name, param in op_param_dict.items():
- if param is None:
- param = {}
- op = eval(op_name)(**param)
- ops.append(op)
- return ops
-
-
-class Resize():
- def __init__(self, size=(640, 640), **kwargs):
- self.size = size
-
- def resize_image(self, img):
- resize_h, resize_w = self.size
- ori_h, ori_w = img.shape[:2] # (h, w, c)
- ratio_h = float(resize_h) / ori_h
- ratio_w = float(resize_w) / ori_w
- img = cv2.resize(img, (int(resize_w), int(resize_h)))
- return img, [ratio_h, ratio_w]
-
- def __call__(self, data):
- img = data['image']
- if 'polys' in data:
- text_polys = data['polys']
-
- img_resize, [ratio_h, ratio_w] = self.resize_image(img)
- if 'polys' in data:
- new_boxes = []
- for box in text_polys:
- new_box = []
- for cord in box:
- new_box.append([cord[0] * ratio_w, cord[1] * ratio_h])
- new_boxes.append(new_box)
- data['polys'] = np.array(new_boxes, dtype=np.float32)
- data['image'] = img_resize
- return data
-
-
-class NormalizeImage():
- def __init__(self, scale=None, mean=None, std=None, order='chw', **kwargs):
- if isinstance(scale, str):
- scale = eval(scale)
- self.scale = np.float32(scale if scale is not None else 1.0 / 255.0)
- mean = mean if mean is not None else [0.485, 0.456, 0.406]
- std = std if std is not None else [0.229, 0.224, 0.225]
-
- shape = (3, 1, 1) if order == 'chw' else (1, 1, 3)
- self.mean = np.array(mean).reshape(shape).astype('float32')
- self.std = np.array(std).reshape(shape).astype('float32')
-
- def __call__(self, data):
- img = np.array(data['image'])
- assert isinstance(img,
- np.ndarray), "invalid input 'img' in NormalizeImage"
- data['image'] = (
- img.astype('float32') * self.scale - self.mean) / self.std
- return data
-
-
-class ToCHWImage():
- def __init__(self, **kwargs):
- pass
-
- def __call__(self, data):
- img = np.array(data['image'])
- data['image'] = img.transpose((2, 0, 1))
- return data
-
-
-class KeepKeys():
- def __init__(self, keep_keys, **kwargs):
- self.keep_keys = keep_keys
-
- def __call__(self, data):
- data_list = []
- for key in self.keep_keys:
- data_list.append(data[key])
- return data_list
-
-
-def read_yaml(yaml_path):
- with open(yaml_path, 'rb') as f:
- data = yaml.load(f, Loader=yaml.Loader)
- return data
-
-
-class PicoDetPostProcess():
- def __init__(self,
- labels,
- strides=[8, 16, 32, 64],
- score_threshold=0.4,
- nms_threshold=0.5,
- nms_top_k=1000,
- keep_top_k=100):
- self.labels = labels
- self.strides = strides
- self.score_threshold = score_threshold
- self.nms_threshold = nms_threshold
- self.nms_top_k = nms_top_k
- self.keep_top_k = keep_top_k
-
- def __call__(self, ori_img, img, preds):
- scores, raw_boxes = preds['boxes'], preds['boxes_num']
- batch_size = raw_boxes[0].shape[0]
- reg_max = int(raw_boxes[0].shape[-1] / 4 - 1)
- out_boxes_num = []
- out_boxes_list = []
- results = []
- ori_shape, input_shape, scale_factor = self.img_info(ori_img, img)
-
- for batch_id in range(batch_size):
- # generate centers
- decode_boxes = []
- select_scores = []
- for stride, box_distribute, score in zip(self.strides, raw_boxes,
- scores):
- box_distribute = box_distribute[batch_id]
- score = score[batch_id]
- # centers
- fm_h = input_shape[0] / stride
- fm_w = input_shape[1] / stride
- h_range = np.arange(fm_h)
- w_range = np.arange(fm_w)
- ww, hh = np.meshgrid(w_range, h_range)
- ct_row = (hh.flatten() + 0.5) * stride
- ct_col = (ww.flatten() + 0.5) * stride
- center = np.stack((ct_col, ct_row, ct_col, ct_row), axis=1)
-
- # box distribution to distance
- reg_range = np.arange(reg_max + 1)
- box_distance = box_distribute.reshape((-1, reg_max + 1))
- box_distance = self.softmax(box_distance, axis=1)
- box_distance = box_distance * np.expand_dims(reg_range, axis=0)
- box_distance = np.sum(box_distance, axis=1).reshape((-1, 4))
- box_distance = box_distance * stride
-
- # top K candidate
- topk_idx = np.argsort(score.max(axis=1))[::-1]
- topk_idx = topk_idx[:self.nms_top_k]
- center = center[topk_idx]
- score = score[topk_idx]
- box_distance = box_distance[topk_idx]
-
- # decode box
- decode_box = center + [-1, -1, 1, 1] * box_distance
-
- select_scores.append(score)
- decode_boxes.append(decode_box)
-
- # nms
- bboxes = np.concatenate(decode_boxes, axis=0)
- confidences = np.concatenate(select_scores, axis=0)
- picked_box_probs = []
- picked_labels = []
- for class_index in range(0, confidences.shape[1]):
- probs = confidences[:, class_index]
- mask = probs > self.score_threshold
- probs = probs[mask]
- if probs.shape[0] == 0:
- continue
- subset_boxes = bboxes[mask, :]
- box_probs = np.concatenate(
- [subset_boxes, probs.reshape(-1, 1)], axis=1)
- box_probs = self.hard_nms(
- box_probs,
- iou_threshold=self.nms_threshold,
- top_k=self.keep_top_k, )
- picked_box_probs.append(box_probs)
- picked_labels.extend([class_index] * box_probs.shape[0])
-
- if len(picked_box_probs) == 0:
- out_boxes_list.append(np.empty((0, 4)))
- out_boxes_num.append(0)
-
- else:
- picked_box_probs = np.concatenate(picked_box_probs)
-
- # resize output boxes
- picked_box_probs[:, :4] = self.warp_boxes(
- picked_box_probs[:, :4], ori_shape[batch_id])
- im_scale = np.concatenate([
- scale_factor[batch_id][::-1], scale_factor[batch_id][::-1]
- ])
- picked_box_probs[:, :4] /= im_scale
- # clas score box
- out_boxes_list.append(
- np.concatenate(
- [
- np.expand_dims(
- np.array(picked_labels),
- axis=-1), np.expand_dims(
- picked_box_probs[:, 4], axis=-1),
- picked_box_probs[:, :4]
- ],
- axis=1))
- out_boxes_num.append(len(picked_labels))
-
- out_boxes_list = np.concatenate(out_boxes_list, axis=0)
- out_boxes_num = np.asarray(out_boxes_num).astype(np.int32)
-
- for dt in out_boxes_list:
- clsid, bbox, score = int(dt[0]), dt[2:], dt[1]
- label = self.labels[clsid]
- result = {'bbox': bbox, 'label': label}
- results.append(result)
- return results
-
- def load_layout_dict(self, layout_dict_path):
- with open(layout_dict_path, 'r', encoding='utf-8') as fp:
- labels = fp.readlines()
- return [label.strip('\n') for label in labels]
-
- def warp_boxes(self, boxes, ori_shape):
- """Apply transform to boxes
- """
- width, height = ori_shape[1], ori_shape[0]
- n = len(boxes)
- if n:
- # warp points
- xy = np.ones((n * 4, 3))
- xy[:, :2] = boxes[:, [0, 1, 2, 3, 0, 3, 2, 1]].reshape(
- n * 4, 2) # x1y1, x2y2, x1y2, x2y1
- # xy = xy @ M.T # transform
- xy = (xy[:, :2] / xy[:, 2:3]).reshape(n, 8) # rescale
- # create new boxes
- x = xy[:, [0, 2, 4, 6]]
- y = xy[:, [1, 3, 5, 7]]
- xy = np.concatenate(
- (x.min(1), y.min(1), x.max(1), y.max(1))).reshape(4, n).T
- # clip boxes
- xy[:, [0, 2]] = xy[:, [0, 2]].clip(0, width)
- xy[:, [1, 3]] = xy[:, [1, 3]].clip(0, height)
- return xy.astype(np.float32)
- else:
- return boxes
-
- def img_info(self, ori_img, img):
- origin_shape = ori_img.shape
- resize_shape = img.shape
- im_scale_y = resize_shape[2] / float(origin_shape[0])
- im_scale_x = resize_shape[3] / float(origin_shape[1])
- scale_factor = np.array([im_scale_y, im_scale_x], dtype=np.float32)
- img_shape = np.array(img.shape[2:], dtype=np.float32)
-
- input_shape = np.array(img).astype('float32').shape[2:]
- ori_shape = np.array((img_shape, )).astype('float32')
- scale_factor = np.array((scale_factor, )).astype('float32')
- return ori_shape, input_shape, scale_factor
-
- @staticmethod
- def softmax(x, axis=None):
- def logsumexp(a, axis=None, b=None, keepdims=False):
- a_max = np.amax(a, axis=axis, keepdims=True)
-
- if a_max.ndim > 0:
- a_max[~np.isfinite(a_max)] = 0
- elif not np.isfinite(a_max):
- a_max = 0
-
- tmp = np.exp(a - a_max)
-
- # suppress warnings about log of zero
- with np.errstate(divide='ignore'):
- s = np.sum(tmp, axis=axis, keepdims=keepdims)
- out = np.log(s)
-
- if not keepdims:
- a_max = np.squeeze(a_max, axis=axis)
- out += a_max
- return out
-
- return np.exp(x - logsumexp(x, axis=axis, keepdims=True))
-
- def hard_nms(self, box_scores, iou_threshold, top_k=-1,
- candidate_size=200):
- """
- Args:
- box_scores (N, 5): boxes in corner-form and probabilities.
- iou_threshold: intersection over union threshold.
- top_k: keep top_k results. If k <= 0, keep all the results.
- candidate_size: only consider the candidates with the highest scores.
- Returns:
- picked: a list of indexes of the kept boxes
- """
- scores = box_scores[:, -1]
- boxes = box_scores[:, :-1]
- picked = []
- indexes = np.argsort(scores)
- indexes = indexes[-candidate_size:]
- while len(indexes) > 0:
- current = indexes[-1]
- picked.append(current)
- if 0 < top_k == len(picked) or len(indexes) == 1:
- break
- current_box = boxes[current, :]
- indexes = indexes[:-1]
- rest_boxes = boxes[indexes, :]
- iou = self.iou_of(rest_boxes, np.expand_dims(current_box, axis=0),)
- indexes = indexes[iou <= iou_threshold]
-
- return box_scores[picked, :]
-
- def iou_of(self, boxes0, boxes1, eps=1e-5):
- """Return intersection-over-union (Jaccard index) of boxes.
- Args:
- boxes0 (N, 4): ground truth boxes.
- boxes1 (N or 1, 4): predicted boxes.
- eps: a small number to avoid 0 as denominator.
- Returns:
- iou (N): IoU values.
- """
- overlap_left_top = np.maximum(boxes0[..., :2], boxes1[..., :2])
- overlap_right_bottom = np.minimum(boxes0[..., 2:], boxes1[..., 2:])
-
- overlap_area = self.area_of(overlap_left_top, overlap_right_bottom)
- area0 = self.area_of(boxes0[..., :2], boxes0[..., 2:])
- area1 = self.area_of(boxes1[..., :2], boxes1[..., 2:])
- return overlap_area / (area0 + area1 - overlap_area + eps)
-
- @staticmethod
- def area_of(left_top, right_bottom):
- """Compute the areas of rectangles given two corners.
- Args:
- left_top (N, 2): left top corner.
- right_bottom (N, 2): right bottom corner.
- Returns:
- area (N): return the area.
- """
- hw = np.clip(right_bottom - left_top, 0.0, None)
- return hw[..., 0] * hw[..., 1]
-
-
-def vis_layout(img: np.ndarray, layout_res: list, save_path: str) -> None:
- font = cv2.FONT_HERSHEY_COMPLEX
- font_scale = 1
- font_color = (0, 0, 255)
- font_thickness = 1
-
- tmp_img = copy.deepcopy(img)
- for v in layout_res:
- bbox = np.round(v['bbox']).astype(np.int32)
- label = v['label']
-
- start_point = (bbox[0], bbox[1])
- end_point = (bbox[2], bbox[3])
-
- cv2.rectangle(tmp_img, start_point, end_point, (0, 255, 0), 2)
-
- (w, h), _ = cv2.getTextSize(label, font, font_scale, font_thickness)
- put_point = start_point[0], start_point[1] + h
- cv2.putText(tmp_img, label, put_point, font, font_scale,
- font_color, font_thickness)
-
- cv2.imwrite(save_path, tmp_img)
- print(f'The infer result has saved in {save_path}')
diff --git a/python/rapid_structure/rapid_orientation/__init__.py b/python/rapid_structure/rapid_orientation/__init__.py
deleted file mode 100644
index 336271c..0000000
--- a/python/rapid_structure/rapid_orientation/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-from .rapid_orientation import RapidOrientation
diff --git a/python/rapid_structure/rapid_orientation/config.yaml b/python/rapid_structure/rapid_orientation/config.yaml
deleted file mode 100644
index 78847b2..0000000
--- a/python/rapid_structure/rapid_orientation/config.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-model_path: models/rapid_orientation.onnx
-
-use_cuda: false
-CUDAExecutionProvider:
- device_id: 0
- arena_extend_strategy: kNextPowerOfTwo
- cudnn_conv_algo_search: EXHAUSTIVE
- do_copy_in_default_stream: true
-
-PreProcess:
- - ResizeImage:
- resize_short: 256
- - CropImage:
- size: 224
- - NormalizeImage:
- - ToCHWImage:
diff --git a/python/rapid_structure/rapid_orientation/models/.gitkeep b/python/rapid_structure/rapid_orientation/models/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/python/rapid_structure/rapid_orientation/rapid_orientation.py b/python/rapid_structure/rapid_orientation/rapid_orientation.py
deleted file mode 100644
index 7694ab9..0000000
--- a/python/rapid_structure/rapid_orientation/rapid_orientation.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-import argparse
-import time
-from pathlib import Path
-import cv2
-
-import numpy as np
-import yaml
-
-from .utils import OrtInferSession, create_operators
-
-root_dir = Path(__file__).resolve().parent
-
-
-class RapidOrientation():
- def __init__(self, model_path: str = None):
- config_path = str(root_dir / 'config.yaml')
- config = self.read_yaml(config_path)
- if model_path is None:
- model_path = str(root_dir / 'models' / 'rapid_orientation.onnx')
- config['model_path'] = model_path
-
- self.session = OrtInferSession(config)
- self.labels = self.session.get_metadata()['character'].splitlines()
-
- self.preprocess_ops = create_operators(config["PreProcess"])
-
- def __call__(self, images):
- s = time.time()
- for ops in self.preprocess_ops:
- images = ops(images)
- image = np.array(images)[None, ...]
-
- pred_output = self.session(image)[0]
-
- pred_output = pred_output.squeeze()
- pred_idx = np.argmax(pred_output)
- pred_txt = self.labels[pred_idx]
- elapse = time.time() - s
- return pred_txt, elapse
-
- @staticmethod
- def read_yaml(yaml_path):
- with open(yaml_path, 'rb') as f:
- data = yaml.load(f, Loader=yaml.Loader)
- return data
-
-
-def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('-img', '--img_path', type=str, required=True,
- help='Path to image for layout.')
- parser.add_argument('-m', '--model_path', type=str,
- default=str(root_dir / 'models' /
- 'rapid_orientation.onnx'),
- help='The model path used for inference.')
- args = parser.parse_args()
-
- orientation_engine = RapidOrientation(args.model_path)
-
- img = cv2.imread(args.img_path)
- orientaion_result, _ = orientation_engine(img)
- print(orientaion_result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/python/rapid_structure/rapid_orientation/utils.py b/python/rapid_structure/rapid_orientation/utils.py
deleted file mode 100644
index f2a43c5..0000000
--- a/python/rapid_structure/rapid_orientation/utils.py
+++ /dev/null
@@ -1,169 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-import importlib
-from pathlib import Path
-import warnings
-
-import cv2
-import numpy as np
-from onnxruntime import (GraphOptimizationLevel, InferenceSession,
- SessionOptions, get_available_providers, get_device)
-
-
-class OrtInferSession():
- def __init__(self, config):
- sess_opt = SessionOptions()
- sess_opt.log_severity_level = 4
- sess_opt.enable_cpu_mem_arena = False
- sess_opt.graph_optimization_level = GraphOptimizationLevel.ORT_ENABLE_ALL
-
- cuda_ep = 'CUDAExecutionProvider'
- cpu_ep = 'CPUExecutionProvider'
- cpu_provider_options = {"arena_extend_strategy": "kSameAsRequested", }
-
- EP_list = []
- if config['use_cuda'] and get_device() == 'GPU' \
- and cuda_ep in get_available_providers():
- EP_list = [(cuda_ep, config[cuda_ep])]
- EP_list.append((cpu_ep, cpu_provider_options))
-
- self._verify_model(config['model_path'])
- self.session = InferenceSession(config['model_path'],
- sess_options=sess_opt,
- providers=EP_list)
-
- has_cuda_ep = cuda_ep not in self.session.get_providers()
- if config['use_cuda'] and has_cuda_ep:
- warnings.warn(f'{cuda_ep} is not avaiable for current env,'
- f'the inference part is automatically shifted to '
- f'be executed under {cpu_ep}. '
- f'Please ensure the installed onnxruntime-gpu '
- f' version matches your cuda and cudnn version, '
- f'you can check their relations from the offical web site: '
- f'https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html',
- RuntimeWarning)
-
- def __call__(self, input_content: np.ndarray) -> np.ndarray:
- input_dict = dict(zip(self.get_input_names(), [input_content]))
- try:
- return self.session.run(self.get_output_names(), input_dict)
- except Exception as e:
- raise ONNXRuntimeError('ONNXRuntime inferece failed.') from e
-
- def get_input_names(self, ):
- return [v.name for v in self.session.get_inputs()]
-
- def get_output_names(self,):
- return [v.name for v in self.session.get_outputs()]
-
- def get_metadata(self):
- meta_dict = self.session.get_modelmeta().custom_metadata_map
- return meta_dict
-
- @staticmethod
- def _verify_model(model_path):
- model_path = Path(model_path)
- if not model_path.exists():
- raise FileNotFoundError(f'{model_path} does not exists.')
- if not model_path.is_file():
- raise FileExistsError(f'{model_path} is not a file.')
-
-
-class ONNXRuntimeError(Exception):
- pass
-
-
-def create_operators(params):
- """
- create operators based on the config
-
- Args:
- params(list): a dict list, used to create some operators
- """
- assert isinstance(params, list), ('operator config should be a list')
- mod = importlib.import_module(__name__)
- ops = []
- for operator in params:
- assert isinstance(operator,
- dict) and len(operator) == 1, "yaml format error"
- op_name = list(operator)[0]
- param = {} if operator[op_name] is None else operator[op_name]
- op = getattr(mod, op_name)(**param)
- ops.append(op)
- return ops
-
-
-class ResizeImage():
- def __init__(self, size=None, resize_short=None):
- if resize_short is not None and resize_short > 0:
- self.resize_short = resize_short
- self.w, self.h = None, None
- elif size is not None:
- self.resize_short = None
- self.w = size if isinstance(size, int) else size[0]
- self.h = size if isinstance(size, int) else size[1]
- else:
- raise ValueError("invalid params for ReisizeImage for '\
- 'both 'size' and 'resize_short' are None")
-
- def __call__(self, img: np.ndarray):
- img_h, img_w = img.shape[:2]
-
- if self.resize_short:
- percent = float(self.resize_short) / min(img_w, img_h)
- w = int(round(img_w * percent))
- h = int(round(img_h * percent))
- else:
- w = self.w
- h = self.h
- return cv2.resize(img, (w, h))
-
-
-class NormalizeImage():
- def __init__(self,):
- self.scale = np.float32(1.0 / 255.0)
- mean = [0.485, 0.456, 0.406]
- std = [0.229, 0.224, 0.225]
-
- shape = 1, 1, 3
- self.mean = np.array(mean).reshape(shape).astype('float32')
- self.std = np.array(std).reshape(shape).astype('float32')
-
- def __call__(self, img):
- img = np.array(img).astype(np.float32)
- img = (img * self.scale - self.mean) / self.std
- return img.astype(np.float32)
-
-
-class ToCHWImage():
- def __init__(self):
- pass
-
- def __call__(self, img):
- img = np.array(img)
- return img.transpose((2, 0, 1))
-
-
-class CropImage():
- def __init__(self, size):
- self.size = size
- if isinstance(size, int):
- self.size = (size, size)
-
- def __call__(self, img):
- w, h = self.size
- img_h, img_w = img.shape[:2]
-
- if img_h < h or img_w < w:
- raise ValueError(
- f"The size({h}, {w}) of CropImage must be greater than "
- f"size({img_h}, {img_w}) of image."
- )
-
- w_start = (img_w - w) // 2
- h_start = (img_h - h) // 2
-
- w_end = w_start + w
- h_end = h_start + h
- return img[h_start:h_end, w_start:w_end, :]
diff --git a/python/rapid_structure/rapid_table/__init__.py b/python/rapid_structure/rapid_table/__init__.py
deleted file mode 100644
index e4a5ed5..0000000
--- a/python/rapid_structure/rapid_table/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-from .rapid_table import RapidTable
diff --git a/python/rapid_structure/rapid_table/models/.gitkeep b/python/rapid_structure/rapid_table/models/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/python/rapid_structure/rapid_table/rapid_table.py b/python/rapid_structure/rapid_table/rapid_table.py
deleted file mode 100644
index 27027e6..0000000
--- a/python/rapid_structure/rapid_table/rapid_table.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-import argparse
-import copy
-import time
-from pathlib import Path
-
-import cv2
-import numpy as np
-from rapidocr_onnxruntime import RapidOCR
-
-from .table_matcher import TableMatch
-from .table_structure import TableStructurer
-
-root_dir = Path(__file__).resolve().parent
-
-
-class RapidTable():
- def __init__(self, model_path: str = None):
- self.ocr_sys = RapidOCR()
-
- if model_path is None:
- model_path = str(root_dir / 'models' / 'en_ppstructure_mobile_v2_SLANet.onnx')
-
- self.table_structure = TableStructurer(model_path)
- self.table_matcher = TableMatch()
-
- def __call__(self, img):
- s = time.time()
- dt_boxes, rec_res = self._ocr(copy.deepcopy(img))
-
- structure_res, _ = self.table_structure(copy.deepcopy(img))
- pred_html = self.table_matcher(structure_res, dt_boxes, rec_res)
-
- elapse = time.time() - s
- return pred_html, elapse
-
- def _ocr(self, img):
- h, w = img.shape[:2]
-
- ocr_result, _ = self.ocr_sys(img)
- dt_boxes, rec_res, scores = list(zip(*ocr_result))
- rec_res = list(zip(rec_res, scores))
-
- r_boxes = []
- for box in dt_boxes:
- box = np.array(box)
- x_min = max(0, box[:, 0].min() - 1)
- x_max = min(w, box[:, 0].max() + 1)
- y_min = max(0, box[:, 1].min() - 1)
- y_max = min(h, box[:, 1].max() + 1)
- box = [x_min, y_min, x_max, y_max]
- r_boxes.append(box)
- dt_boxes = np.array(r_boxes)
- return dt_boxes, rec_res
-
-
-def vis_table(table_res: str, save_path: str) -> None:
- style_res = ''''''
- prefix_table, suffix_table = table_res.split('')
- new_table_res = f'{prefix_table}{style_res}{suffix_table}'
- with open(save_path, 'w', encoding='utf-8') as f:
- f.write(new_table_res)
- print(f'The infer result has saved in {save_path}')
-
-
-def main() -> None:
- parser = argparse.ArgumentParser()
- parser.add_argument('-v', '--vis', action='store_true',
- help='Wheter to visualize the layout results.')
- parser.add_argument('-img', '--img_path', type=str, required=True,
- help='Path to image for layout.')
- parser.add_argument('-m', '--model_path', type=str,
- default=str(root_dir / 'models' / 'en_ppstructure_mobile_v2_SLANet.onnx'),
- help='The model path used for inference.')
- args = parser.parse_args()
-
- rapid_table = RapidTable(args.model_path)
-
- img = cv2.imread(args.img_path)
- table_html_str, elapse = rapid_table(img)
- print(table_html_str)
-
- if args.vis:
- img_path = Path(args.img_path)
- save_path = img_path.resolve().parent / f'vis_{img_path.stem}.html'
- vis_table(table_html_str, str(save_path))
-
-
-if __name__ == '__main__':
- main()
diff --git a/python/rapid_structure/rapid_table/table_matcher/__init__.py b/python/rapid_structure/rapid_table/table_matcher/__init__.py
deleted file mode 100644
index 9bff7d7..0000000
--- a/python/rapid_structure/rapid_table/table_matcher/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-from .matcher import TableMatch
diff --git a/python/rapid_structure/rapid_table/table_matcher/matcher.py b/python/rapid_structure/rapid_table/table_matcher/matcher.py
deleted file mode 100644
index d60ddb1..0000000
--- a/python/rapid_structure/rapid_table/table_matcher/matcher.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# copyright (c) 2022 PaddlePaddle Authors. All Rights Reserve.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# -*- encoding: utf-8 -*-
-import numpy as np
-
-from .utils import compute_iou, deal_bb, distance
-
-
-class TableMatch():
- def __init__(self, filter_ocr_result=True, use_master=False):
- self.filter_ocr_result = filter_ocr_result
- self.use_master = use_master
-
- def __call__(self, structure_res, dt_boxes, rec_res):
- pred_structures, pred_bboxes = structure_res
- if self.filter_ocr_result:
- dt_boxes, rec_res = self._filter_ocr_result(pred_bboxes, dt_boxes,
- rec_res)
- matched_index = self.match_result(dt_boxes, pred_bboxes)
- pred_html, pred = self.get_pred_html(pred_structures,
- matched_index,
- rec_res)
- return pred_html
-
- def match_result(self, dt_boxes, pred_bboxes):
- matched = {}
- for i, gt_box in enumerate(dt_boxes):
- distances = []
- for j, pred_box in enumerate(pred_bboxes):
- if len(pred_box) == 8:
- pred_box = [
- np.min(pred_box[0::2]), np.min(pred_box[1::2]),
- np.max(pred_box[0::2]), np.max(pred_box[1::2])
- ]
- distances.append((distance(gt_box, pred_box),
- 1. - compute_iou(gt_box, pred_box)
- )) # compute iou and l1 distance
- sorted_distances = distances.copy()
- # select det box by iou and l1 distance
- sorted_distances = sorted(
- sorted_distances, key=lambda item: (item[1], item[0]))
- if distances.index(sorted_distances[0]) not in matched.keys():
- matched[distances.index(sorted_distances[0])] = [i]
- else:
- matched[distances.index(sorted_distances[0])].append(i)
- return matched
-
- def get_pred_html(self, pred_structures, matched_index, ocr_contents):
- end_html = []
- td_index = 0
- for tag in pred_structures:
- if '' in tag:
- if ' | ' == tag:
- end_html.extend('')
- if td_index in matched_index.keys():
- b_with = False
- if '' in ocr_contents[matched_index[td_index][0]] \
- and len(matched_index[td_index]) > 1:
- b_with = True
- end_html.extend('')
- for i, td_index_index in enumerate(matched_index[td_index]):
- content = ocr_contents[td_index_index][0]
- if len(matched_index[td_index]) > 1:
- if len(content) == 0:
- continue
-
- if content[0] == ' ':
- content = content[1:]
-
- if '' in content:
- content = content[3:]
-
- if '' in content:
- content = content[:-4]
-
- if len(content) == 0:
- continue
-
- if i != len(matched_index[td_index]) - 1 \
- and ' ' != content[-1]:
- content += ' '
- end_html.extend(content)
- if b_with:
- end_html.extend('')
-
- if ' | | ' == tag:
- end_html.append('')
- else:
- end_html.append(tag)
- td_index += 1
- else:
- end_html.append(tag)
- return ''.join(end_html), end_html
-
- def get_pred_html_master(self, pred_structures, matched_index,
- ocr_contents):
- end_html = []
- td_index = 0
- for token in pred_structures:
- if '' in token:
- txt = ''
- b_with = False
- if td_index in matched_index.keys():
- if '' in ocr_contents[matched_index[td_index][
- 0]] and len(matched_index[td_index]) > 1:
- b_with = True
- for i, td_index_index in enumerate(matched_index[td_index]):
- content = ocr_contents[td_index_index][0]
- if len(matched_index[td_index]) > 1:
- if len(content) == 0:
- continue
- if content[0] == ' ':
- content = content[1:]
- if '' in content:
- content = content[3:]
- if '' in content:
- content = content[:-4]
- if len(content) == 0:
- continue
- if i != len(matched_index[
- td_index]) - 1 and ' ' != content[-1]:
- content += ' '
- txt += content
- if b_with:
- txt = '{}'.format(txt)
- if ' | ' == token:
- token = '{} | '.format(txt)
- else:
- token = '{}'.format(txt)
- td_index += 1
- token = deal_eb_token(token)
- end_html.append(token)
- html = ''.join(end_html)
- html = deal_bb(html)
- return html, end_html
-
- def _filter_ocr_result(self, pred_bboxes, dt_boxes, rec_res):
- y1 = pred_bboxes[:, 1::2].min()
- new_dt_boxes = []
- new_rec_res = []
-
- for box, rec in zip(dt_boxes, rec_res):
- if np.max(box[1::2]) < y1:
- continue
- new_dt_boxes.append(box)
- new_rec_res.append(rec)
- return new_dt_boxes, new_rec_res
diff --git a/python/rapid_structure/rapid_table/table_matcher/utils.py b/python/rapid_structure/rapid_table/table_matcher/utils.py
deleted file mode 100644
index bb2b0cb..0000000
--- a/python/rapid_structure/rapid_table/table_matcher/utils.py
+++ /dev/null
@@ -1,244 +0,0 @@
-# copyright (c) 2022 PaddlePaddle Authors. All Rights Reserve.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# -*- encoding: utf-8 -*-
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-import re
-
-
-def deal_isolate_span(thead_part):
- """
- Deal with isolate span cases in this function.
- It causes by wrong prediction in structure recognition model.
- eg. predict | to | rowspan="2">.
- :param thead_part:
- :return:
- """
- # 1. find out isolate span tokens.
- isolate_pattern = " | rowspan=\"(\d)+\" colspan=\"(\d)+\">|" \
- " | colspan=\"(\d)+\" rowspan=\"(\d)+\">|" \
- " | rowspan=\"(\d)+\">|" \
- " | colspan=\"(\d)+\">"
- isolate_iter = re.finditer(isolate_pattern, thead_part)
- isolate_list = [i.group() for i in isolate_iter]
-
- # 2. find out span number, by step 1 results.
- span_pattern = " rowspan=\"(\d)+\" colspan=\"(\d)+\"|" \
- " colspan=\"(\d)+\" rowspan=\"(\d)+\"|" \
- " rowspan=\"(\d)+\"|" \
- " colspan=\"(\d)+\""
- corrected_list = []
- for isolate_item in isolate_list:
- span_part = re.search(span_pattern, isolate_item)
- spanStr_in_isolateItem = span_part.group()
- # 3. merge the span number into the span token format string.
- if spanStr_in_isolateItem is not None:
- corrected_item = ' | '.format(spanStr_in_isolateItem)
- corrected_list.append(corrected_item)
- else:
- corrected_list.append(None)
-
- # 4. replace original isolated token.
- for corrected_item, isolate_item in zip(corrected_list, isolate_list):
- if corrected_item is not None:
- thead_part = thead_part.replace(isolate_item, corrected_item)
- else:
- pass
- return thead_part
-
-
-def deal_duplicate_bb(thead_part):
- """
- Deal duplicate or after replace.
- Keep one in a | token.
- :param thead_part:
- :return:
- """
- # 1. find out | in .
- td_pattern = "(.+?) | |" \
- "(.+?) | |" \
- "(.+?) | |" \
- "(.+?) | |" \
- "(.*?) | "
- td_iter = re.finditer(td_pattern, thead_part)
- td_list = [t.group() for t in td_iter]
-
- # 2. is multiply in | or not?
- new_td_list = []
- for td_item in td_list:
- if td_item.count('') > 1 or td_item.count('') > 1:
- # multiply in | case.
- # 1. remove all
- td_item = td_item.replace('', '').replace('', '')
- # 2. replace -> , -> .
- td_item = td_item.replace('', ' | ').replace(' | ',
- '')
- new_td_list.append(td_item)
- else:
- new_td_list.append(td_item)
-
- # 3. replace original thead part.
- for td_item, new_td_item in zip(td_list, new_td_list):
- thead_part = thead_part.replace(td_item, new_td_item)
- return thead_part
-
-
-def deal_bb(result_token):
- """
- In our opinion, always occurs in text's context.
- This function will find out all tokens in and insert by manual.
- :param result_token:
- :return:
- """
- # find out parts.
- thead_pattern = '(.*?)'
- if re.search(thead_pattern, result_token) is None:
- return result_token
- thead_part = re.search(thead_pattern, result_token).group()
- origin_thead_part = copy.deepcopy(thead_part)
-
- # check "rowspan" or "colspan" occur in parts or not .
- span_pattern = "| | | | | | "
- span_iter = re.finditer(span_pattern, thead_part)
- span_list = [s.group() for s in span_iter]
- has_span_in_head = True if len(span_list) > 0 else False
-
- if not has_span_in_head:
- # not include "rowspan" or "colspan" branch 1.
- # 1. replace | to | , and | to
- # 2. it is possible to predict text include or by Text-line recognition,
- # so we replace to , and to
- thead_part = thead_part.replace('', ' | ')\
- .replace(' | ', '')\
- .replace('', '')\
- .replace('', '')
- else:
- # include "rowspan" or "colspan" branch 2.
- # Firstly, we deal rowspan or colspan cases.
- # 1. replace > to >
- # 2. replace to
- # 3. it is possible to predict text include or by Text-line recognition,
- # so we replace to , and to
-
- # Secondly, deal ordinary cases like branch 1
-
- # replace ">" to ""
- replaced_span_list = []
- for sp in span_list:
- replaced_span_list.append(sp.replace('>', '>'))
- for sp, rsp in zip(span_list, replaced_span_list):
- thead_part = thead_part.replace(sp, rsp)
-
- # replace "" to ""
- thead_part = thead_part.replace('', '')
-
- # remove duplicated by re.sub
- mb_pattern = "()+"
- single_b_string = ""
- thead_part = re.sub(mb_pattern, single_b_string, thead_part)
-
- mgb_pattern = "()+"
- single_gb_string = ""
- thead_part = re.sub(mgb_pattern, single_gb_string, thead_part)
-
- # ordinary cases like branch 1
- thead_part = thead_part.replace('', ' | ').replace('',
- '')
-
- # convert back to , empty cell has no .
- # but space cell( ) is suitable for | |
- thead_part = thead_part.replace(' | ', ' | ')
- # deal with duplicated
- thead_part = deal_duplicate_bb(thead_part)
- # deal with isolate span tokens, which causes by wrong predict by structure prediction.
- # eg.PMC5994107_011_00.png
- thead_part = deal_isolate_span(thead_part)
- # replace original result with new thead part.
- result_token = result_token.replace(origin_thead_part, thead_part)
- return result_token
-
-
-def deal_eb_token(master_token):
- """
- post process with , , ...
- emptyBboxTokenDict = {
- "[]": '',
- "[' ']": '',
- "['', ' ', '']": '',
- "['\\u2028', '\\u2028']": '',
- "['', ' ', '']": '',
- "['', '']": '',
- "['', ' ', '']": '',
- "['', '', '', '']": '',
- "['', '', ' ', '', '']": '',
- "['', '']": '',
- "['', ' ', '\\u2028', ' ', '\\u2028', ' ', '']": '',
- }
- :param master_token:
- :return:
- """
- master_token = master_token.replace('', ' | ')
- master_token = master_token.replace('', ' | ')
- master_token = master_token.replace('', ' | ')
- master_token = master_token.replace('', '\u2028\u2028 | ')
- master_token = master_token.replace('', ' | ')
- master_token = master_token.replace('', ' | ')
- master_token = master_token.replace('', ' | ')
- master_token = master_token.replace('',
- ' | ')
- master_token = master_token.replace('',
- ' | ')
- master_token = master_token.replace('', ' | ')
- master_token = master_token.replace('',
- ' \u2028 \u2028 | ')
- return master_token
-
-
-def distance(box_1, box_2):
- x1, y1, x2, y2 = box_1
- x3, y3, x4, y4 = box_2
- dis = abs(x3 - x1) + abs(y3 - y1) + abs(x4 - x2) + abs(y4 - y2)
- dis_2 = abs(x3 - x1) + abs(y3 - y1)
- dis_3 = abs(x4 - x2) + abs(y4 - y2)
- return dis + min(dis_2, dis_3)
-
-
-def compute_iou(rec1, rec2):
- """
- computing IoU
- :param rec1: (y0, x0, y1, x1), which reflects
- (top, left, bottom, right)
- :param rec2: (y0, x0, y1, x1)
- :return: scala value of IoU
- """
- # computing area of each rectangles
- S_rec1 = (rec1[2] - rec1[0]) * (rec1[3] - rec1[1])
- S_rec2 = (rec2[2] - rec2[0]) * (rec2[3] - rec2[1])
-
- # computing the sum_area
- sum_area = S_rec1 + S_rec2
-
- # find the each edge of intersect rectangle
- left_line = max(rec1[1], rec2[1])
- right_line = min(rec1[3], rec2[3])
- top_line = max(rec1[0], rec2[0])
- bottom_line = min(rec1[2], rec2[2])
-
- # judge if there is an intersect
- if left_line >= right_line or top_line >= bottom_line:
- return 0.0
- else:
- intersect = (right_line - left_line) * (bottom_line - top_line)
- return (intersect / (sum_area - intersect)) * 1.0
diff --git a/python/rapid_structure/rapid_table/table_structure/__init__.py b/python/rapid_structure/rapid_table/table_structure/__init__.py
deleted file mode 100644
index a548391..0000000
--- a/python/rapid_structure/rapid_table/table_structure/__init__.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-from .table_structure import TableStructurer
diff --git a/python/rapid_structure/rapid_table/table_structure/table_structure.py b/python/rapid_structure/rapid_table/table_structure/table_structure.py
deleted file mode 100644
index f63fcb3..0000000
--- a/python/rapid_structure/rapid_table/table_structure/table_structure.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-import time
-import numpy as np
-
-from .utils import (OrtInferSession, TableLabelDecode, TablePreprocess)
-
-
-class TableStructurer():
- def __init__(self, model_path: str):
- self.preprocess_op = TablePreprocess()
-
- self.session = OrtInferSession(model_path)
-
- self.character = self.session.get_metadata()
- self.postprocess_op = TableLabelDecode(self.character)
-
- def __call__(self, img):
- starttime = time.time()
- data = {'image': img}
- data = self.preprocess_op(data)
- img = data[0]
- if img is None:
- return None, 0
- img = np.expand_dims(img, axis=0)
- img = img.copy()
-
- outputs = self.session(img)
-
- preds = {
- 'loc_preds': outputs[0],
- 'structure_probs': outputs[1]
- }
-
- shape_list = np.expand_dims(data[-1], axis=0)
- post_result = self.postprocess_op(preds, [shape_list])
-
- bbox_list = post_result['bbox_batch_list'][0]
-
- structure_str_list = post_result['structure_batch_list'][0]
- structure_str_list = structure_str_list[0]
- structure_str_list = [
- '', '', ''
- ] + structure_str_list + ['
', '', '']
- elapse = time.time() - starttime
- return (structure_str_list, bbox_list), elapse
diff --git a/python/rapid_structure/rapid_table/table_structure/utils.py b/python/rapid_structure/rapid_table/table_structure/utils.py
deleted file mode 100644
index 1d27c9b..0000000
--- a/python/rapid_structure/rapid_table/table_structure/utils.py
+++ /dev/null
@@ -1,349 +0,0 @@
-# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-from pathlib import Path
-
-import cv2
-import numpy as np
-from onnxruntime import (GraphOptimizationLevel, InferenceSession,
- SessionOptions)
-
-
-class OrtInferSession():
- def __init__(self, onnx_path: str):
- self._verify_model(onnx_path)
-
- sess_opt = SessionOptions()
- sess_opt.log_severity_level = 4
- sess_opt.enable_cpu_mem_arena = False
- sess_opt.graph_optimization_level = GraphOptimizationLevel.ORT_ENABLE_ALL
-
- cpu_ep = 'CPUExecutionProvider'
- cpu_provider_options = {"arena_extend_strategy": "kSameAsRequested",}
- EP_list = [(cpu_ep, cpu_provider_options)]
-
- self._verify_model(onnx_path)
- self.session = InferenceSession(onnx_path,
- sess_options=sess_opt,
- providers=EP_list)
-
- def __call__(self, input_content: np.ndarray) -> np.ndarray:
- input_dict = dict(zip(self.get_input_names(), [input_content]))
- try:
- return self.session.run(self.get_output_names(), input_dict)
- except Exception as e:
- raise ONNXRuntimeError('ONNXRuntime inferece failed.') from e
-
- def get_input_names(self, ):
- return [v.name for v in self.session.get_inputs()]
-
- def get_output_names(self,):
- return [v.name for v in self.session.get_outputs()]
-
- def get_metadata(self, key: str = 'character') -> list:
- meta_dict = self.session.get_modelmeta().custom_metadata_map
- content_list = meta_dict[key].splitlines()
- return content_list
-
- @staticmethod
- def _verify_model(model_path):
- model_path = Path(model_path)
- if not model_path.exists():
- raise FileNotFoundError(f'{model_path} does not exists.')
- if not model_path.is_file():
- raise FileExistsError(f'{model_path} is not a file.')
-
-
-class ONNXRuntimeError(Exception):
- pass
-
-
-class TableLabelDecode():
- """ """
- def __init__(self,
- dict_character,
- merge_no_span_structure=True,
- **kwargs):
- if merge_no_span_structure:
- if " | " not in dict_character:
- dict_character.append(" | ")
- if "" in dict_character:
- dict_character.remove(" | ")
-
- dict_character = self.add_special_char(dict_character)
- self.dict = {}
- for i, char in enumerate(dict_character):
- self.dict[char] = i
- self.character = dict_character
- self.td_token = [' | ', ' | | ']
-
- def __call__(self, preds, batch=None):
- structure_probs = preds['structure_probs']
- bbox_preds = preds['loc_preds']
- shape_list = batch[-1]
- result = self.decode(structure_probs, bbox_preds, shape_list)
- if len(batch) == 1: # only contains shape
- return result
-
- label_decode_result = self.decode_label(batch)
- return result, label_decode_result
-
- def decode(self, structure_probs, bbox_preds, shape_list):
- """convert text-label into text-index.
- """
- ignored_tokens = self.get_ignored_tokens()
- end_idx = self.dict[self.end_str]
-
- structure_idx = structure_probs.argmax(axis=2)
- structure_probs = structure_probs.max(axis=2)
-
- structure_batch_list = []
- bbox_batch_list = []
- batch_size = len(structure_idx)
- for batch_idx in range(batch_size):
- structure_list = []
- bbox_list = []
- score_list = []
- for idx in range(len(structure_idx[batch_idx])):
- char_idx = int(structure_idx[batch_idx][idx])
- if idx > 0 and char_idx == end_idx:
- break
-
- if char_idx in ignored_tokens:
- continue
-
- text = self.character[char_idx]
- if text in self.td_token:
- bbox = bbox_preds[batch_idx, idx]
- bbox = self._bbox_decode(bbox, shape_list[batch_idx])
- bbox_list.append(bbox)
- structure_list.append(text)
- score_list.append(structure_probs[batch_idx, idx])
- structure_batch_list.append([structure_list, np.mean(score_list)])
- bbox_batch_list.append(np.array(bbox_list))
- result = {
- 'bbox_batch_list': bbox_batch_list,
- 'structure_batch_list': structure_batch_list,
- }
- return result
-
- def decode_label(self, batch):
- """convert text-label into text-index.
- """
- structure_idx = batch[1]
- gt_bbox_list = batch[2]
- shape_list = batch[-1]
- ignored_tokens = self.get_ignored_tokens()
- end_idx = self.dict[self.end_str]
-
- structure_batch_list = []
- bbox_batch_list = []
- batch_size = len(structure_idx)
- for batch_idx in range(batch_size):
- structure_list = []
- bbox_list = []
- for idx in range(len(structure_idx[batch_idx])):
- char_idx = int(structure_idx[batch_idx][idx])
- if idx > 0 and char_idx == end_idx:
- break
- if char_idx in ignored_tokens:
- continue
- structure_list.append(self.character[char_idx])
-
- bbox = gt_bbox_list[batch_idx][idx]
- if bbox.sum() != 0:
- bbox = self._bbox_decode(bbox, shape_list[batch_idx])
- bbox_list.append(bbox)
- structure_batch_list.append(structure_list)
- bbox_batch_list.append(bbox_list)
- result = {
- 'bbox_batch_list': bbox_batch_list,
- 'structure_batch_list': structure_batch_list,
- }
- return result
-
- def _bbox_decode(self, bbox, shape):
- h, w, ratio_h, ratio_w, pad_h, pad_w = shape
- bbox[0::2] *= w
- bbox[1::2] *= h
- return bbox
-
- def get_ignored_tokens(self):
- beg_idx = self.get_beg_end_flag_idx("beg")
- end_idx = self.get_beg_end_flag_idx("end")
- return [beg_idx, end_idx]
-
- def get_beg_end_flag_idx(self, beg_or_end):
- if beg_or_end == "beg":
- idx = np.array(self.dict[self.beg_str])
- elif beg_or_end == "end":
- idx = np.array(self.dict[self.end_str])
- else:
- assert False, "unsupport type %s in get_beg_end_flag_idx" \
- % beg_or_end
- return idx
-
- def add_special_char(self, dict_character):
- self.beg_str = "sos"
- self.end_str = "eos"
- dict_character = dict_character
- dict_character = [self.beg_str] + dict_character + [self.end_str]
- return dict_character
-
-
-class TablePreprocess():
- def __init__(self):
- self.table_max_len = 488
- self.build_pre_process_list()
- self.ops = self.create_operators()
-
- def __call__(self, data):
- """ transform """
- if self.ops is None:
- self.ops = []
-
- for op in self.ops:
- data = op(data)
- if data is None:
- return None
- return data
-
- def create_operators(self,):
- """
- create operators based on the config
-
- Args:
- params(list): a dict list, used to create some operators
- """
- assert isinstance(self.pre_process_list, list), ('operator config should be a list')
- ops = []
- for operator in self.pre_process_list:
- assert isinstance(operator,
- dict) and len(operator) == 1, "yaml format error"
- op_name = list(operator)[0]
- param = {} if operator[op_name] is None else operator[op_name]
- op = eval(op_name)(**param)
- ops.append(op)
- return ops
-
- def build_pre_process_list(self):
- resize_op = {'ResizeTableImage': {'max_len': self.table_max_len, }}
- pad_op = {
- 'PaddingTableImage': {
- 'size': [self.table_max_len, self.table_max_len]
- }
- }
- normalize_op = {
- 'NormalizeImage': {
- 'std': [0.229, 0.224, 0.225],
- 'mean': [0.485, 0.456, 0.406],
- 'scale': '1./255.',
- 'order': 'hwc'
- }
- }
- to_chw_op = {'ToCHWImage': None}
- keep_keys_op = {'KeepKeys': {'keep_keys': ['image', 'shape']}}
- self.pre_process_list = [
- resize_op, normalize_op, pad_op, to_chw_op, keep_keys_op
- ]
-
-
-class ResizeTableImage():
- def __init__(self, max_len, resize_bboxes=False, infer_mode=False,
- **kwargs):
- super(ResizeTableImage, self).__init__()
- self.max_len = max_len
- self.resize_bboxes = resize_bboxes
- self.infer_mode = infer_mode
-
- def __call__(self, data):
- img = data['image']
- height, width = img.shape[0:2]
- ratio = self.max_len / (max(height, width) * 1.0)
- resize_h = int(height * ratio)
- resize_w = int(width * ratio)
- resize_img = cv2.resize(img, (resize_w, resize_h))
- if self.resize_bboxes and not self.infer_mode:
- data['bboxes'] = data['bboxes'] * ratio
- data['image'] = resize_img
- data['src_img'] = img
- data['shape'] = np.array([height, width, ratio, ratio])
- data['max_len'] = self.max_len
- return data
-
-
-class PaddingTableImage():
- def __init__(self, size, **kwargs):
- super(PaddingTableImage, self).__init__()
- self.size = size
-
- def __call__(self, data):
- img = data['image']
- pad_h, pad_w = self.size
- padding_img = np.zeros((pad_h, pad_w, 3), dtype=np.float32)
- height, width = img.shape[0:2]
- padding_img[0:height, 0:width, :] = img.copy()
- data['image'] = padding_img
- shape = data['shape'].tolist()
- shape.extend([pad_h, pad_w])
- data['shape'] = np.array(shape)
- return data
-
-
-class NormalizeImage():
- """ normalize image such as substract mean, divide std
- """
- def __init__(self, scale=None, mean=None, std=None, order='chw', **kwargs):
- if isinstance(scale, str):
- scale = eval(scale)
- self.scale = np.float32(scale if scale is not None else 1.0 / 255.0)
- mean = mean if mean is not None else [0.485, 0.456, 0.406]
- std = std if std is not None else [0.229, 0.224, 0.225]
-
- shape = (3, 1, 1) if order == 'chw' else (1, 1, 3)
- self.mean = np.array(mean).reshape(shape).astype('float32')
- self.std = np.array(std).reshape(shape).astype('float32')
-
- def __call__(self, data):
- img = np.array(data['image'])
- assert isinstance(img,
- np.ndarray), "invalid input 'img' in NormalizeImage"
- data['image'] = (
- img.astype('float32') * self.scale - self.mean) / self.std
- return data
-
-
-class ToCHWImage():
- """ convert hwc image to chw image
- """
- def __init__(self, **kwargs):
- pass
-
- def __call__(self, data):
- img = np.array(data['image'])
- data['image'] = img.transpose((2, 0, 1))
- return data
-
-
-class KeepKeys():
- def __init__(self, keep_keys, **kwargs):
- self.keep_keys = keep_keys
-
- def __call__(self, data):
- data_list = []
- for key in self.keep_keys:
- data_list.append(data[key])
- return data_list
diff --git a/python/rapid_structure/requirements.txt b/python/rapid_structure/requirements.txt
deleted file mode 100644
index e6c2ae9..0000000
--- a/python/rapid_structure/requirements.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-numpy>=1.21.6
-opencv_python>=4.6.0.66
-setuptools>=61.2.0
-PyYAML
-pytest>=7.2.1
-pip>=22.3.1
-onnxruntime
-wheel
\ No newline at end of file
diff --git a/python/rapid_structure/setup_layout.py b/python/rapid_structure/setup_layout.py
deleted file mode 100644
index c6e1ca2..0000000
--- a/python/rapid_structure/setup_layout.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-import re
-import subprocess
-import sys
-from pathlib import Path
-
-import setuptools
-
-
-def get_latest_version(package_name):
- output = subprocess.run(["pip", "index", "versions", package_name],
- capture_output=True)
- output = output.stdout.decode('utf-8')
- if output:
- return extract_version(output)
- return None
-
-
-def version_add_one(version, add_loc=-1):
- if version:
- version_list = version.split('.')
- mini_version = str(int(version_list[add_loc]) + 1)
- version_list[add_loc] = mini_version
- new_version = '.'.join(version_list)
- return new_version
- return '0.0.1'
-
-
-def get_readme():
- root_dir = Path(__file__).resolve().parent.parent.parent
- readme_path = str(root_dir / 'docs' / 'doc_whl_rapid_layout.md')
- with open(readme_path, 'r', encoding='utf-8') as f:
- readme = f.read()
- return readme
-
-
-def extract_version(message: str) -> str:
- pattern = r'\d+\.(?:\d+\.)*\d+'
- matched_versions = re.findall(pattern, message)
- if matched_versions:
- return matched_versions[0]
- return ''
-
-
-MODULE_NAME = 'rapid_layout'
-latest_version = get_latest_version(MODULE_NAME)
-VERSION_NUM = version_add_one(latest_version)
-
-# 优先提取commit message中的语义化版本号,如无,则自动加1
-if len(sys.argv) > 2:
- match_str = ' '.join(sys.argv[2:])
- matched_versions = extract_version(match_str)
- if matched_versions:
- VERSION_NUM = matched_versions
-sys.argv = sys.argv[:2]
-
-setuptools.setup(
- name=MODULE_NAME,
- version=VERSION_NUM,
- platforms="Any",
- long_description=get_readme(),
- long_description_content_type='text/markdown',
- description='Tools for document layout analysis based ONNXRuntime.',
- author="SWHL",
- author_email="liekkaskono@163.com",
- url="https://github.com/RapidAI/RapidOCR",
- license='Apache-2.0',
- include_package_data=True,
- install_requires=["onnxruntime>=1.7.0", "PyYAML>=6.0",
- "opencv_python>=4.5.1.48", "numpy>=1.21.6"],
- packages=[MODULE_NAME, f'{MODULE_NAME}.models'],
- package_data={'': ['layout_cdla.onnx', '*.yaml']},
- keywords=[
- 'ppstructure,layout,rapidocr,rapid_layout'
- ],
- classifiers=[
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: 3.8',
- 'Programming Language :: Python :: 3.9',
- 'Programming Language :: Python :: 3.10',
- ],
- entry_points={
- 'console_scripts': [f'{MODULE_NAME}={MODULE_NAME}.{MODULE_NAME}:main']
- }
-)
diff --git a/python/rapid_structure/setup_orientation.py b/python/rapid_structure/setup_orientation.py
deleted file mode 100644
index 64bdf5b..0000000
--- a/python/rapid_structure/setup_orientation.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-import re
-import subprocess
-import sys
-from pathlib import Path
-
-import setuptools
-
-
-def get_latest_version(package_name):
- output = subprocess.run(["pip", "index", "versions", package_name],
- capture_output=True)
- output = output.stdout.decode('utf-8')
- if output:
- return extract_version(output)
- return None
-
-
-def version_add_one(version, add_loc=-1):
- if version:
- version_list = version.split('.')
- mini_version = str(int(version_list[add_loc]) + 1)
- version_list[add_loc] = mini_version
- new_version = '.'.join(version_list)
- return new_version
- return '0.0.1'
-
-
-def get_readme():
- root_dir = Path(__file__).resolve().parent.parent.parent
- readme_path = str(root_dir / 'docs' / 'doc_whl_rapid_orientation.md')
- with open(readme_path, 'r', encoding='utf-8') as f:
- readme = f.read()
- return readme
-
-
-def extract_version(message: str) -> str:
- pattern = r'\d+\.(?:\d+\.)*\d+'
- matched_versions = re.findall(pattern, message)
- if matched_versions:
- return matched_versions[0]
- return ''
-
-
-MODULE_NAME = 'rapid_orientation'
-latest_version = get_latest_version(MODULE_NAME)
-VERSION_NUM = version_add_one(latest_version)
-
-# 优先提取commit message中的语义化版本号,如无,则自动加1
-if len(sys.argv) > 2:
- match_str = ' '.join(sys.argv[2:])
- matched_versions = extract_version(match_str)
- if matched_versions:
- VERSION_NUM = matched_versions
-sys.argv = sys.argv[:2]
-
-setuptools.setup(
- name=MODULE_NAME,
- version=VERSION_NUM,
- platforms="Any",
- long_description=get_readme(),
- long_description_content_type='text/markdown',
- description='Tools for classifying the direction of images containing text based ONNXRuntime.',
- author="SWHL",
- author_email="liekkaskono@163.com",
- url="https://github.com/RapidAI/RapidOCR",
- license='Apache-2.0',
- include_package_data=True,
- install_requires=["onnxruntime>=1.7.0", "PyYAML>=6.0",
- "opencv_python>=4.5.1.48", "numpy>=1.21.6"],
- packages=[MODULE_NAME, f'{MODULE_NAME}.models'],
- package_data={'': ['*.onnx', '*.yaml']},
- keywords=[
- 'ppstructure,layout,rapidocr,rapid_orientation'
- ],
- classifiers=[
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: 3.8',
- 'Programming Language :: Python :: 3.9',
- 'Programming Language :: Python :: 3.10',
- ],
- entry_points={
- 'console_scripts': [f'{MODULE_NAME}={MODULE_NAME}.{MODULE_NAME}:main']
- }
-)
diff --git a/python/rapid_structure/setup_table.py b/python/rapid_structure/setup_table.py
deleted file mode 100644
index 50fa369..0000000
--- a/python/rapid_structure/setup_table.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-import re
-import subprocess
-import sys
-from pathlib import Path
-
-import setuptools
-
-
-def get_latest_version(package_name):
- output = subprocess.run(["pip", "index", "versions", package_name],
- capture_output=True)
- output = output.stdout.decode('utf-8')
- if output:
- return extract_version(output)
- return None
-
-
-def version_add_one(version, add_loc=-1):
- if version:
- version_list = version.split('.')
- mini_version = str(int(version_list[add_loc]) + 1)
- version_list[add_loc] = mini_version
- new_version = '.'.join(version_list)
- return new_version
- return '0.0.1'
-
-
-def get_readme():
- root_dir = Path(__file__).resolve().parent.parent.parent
- readme_path = str(root_dir / 'docs' / 'doc_whl_rapid_table.md')
- with open(readme_path, 'r', encoding='utf-8') as f:
- readme = f.read()
- return readme
-
-
-def extract_version(message: str) -> str:
- pattern = r'\d+\.(?:\d+\.)*\d+'
- matched_versions = re.findall(pattern, message)
- if matched_versions:
- return matched_versions[0]
- return ''
-
-
-MODULE_NAME = 'rapid_table'
-latest_version = get_latest_version(MODULE_NAME)
-VERSION_NUM = version_add_one(latest_version)
-
-# 优先提取commit message中的语义化版本号,如无,则自动加1
-if len(sys.argv) > 2:
- match_str = ' '.join(sys.argv[2:])
- matched_versions = extract_version(match_str)
- if matched_versions:
- VERSION_NUM = matched_versions
-sys.argv = sys.argv[:2]
-
-setuptools.setup(
- name=MODULE_NAME,
- version=VERSION_NUM,
- platforms="Any",
- long_description=get_readme(),
- long_description_content_type='text/markdown',
- description='Tools for parsing table structures based ONNXRuntime.',
- author="SWHL",
- author_email="liekkaskono@163.com",
- url="https://github.com/RapidAI/RapidOCR",
- license='Apache-2.0',
- include_package_data=True,
- install_requires=["onnxruntime>=1.7.0", "PyYAML>=6.0",
- "opencv_python>=4.5.1.48", "numpy>=1.21.6",
- "rapidocr_onnxruntime>=1.1.18"],
- packages=[MODULE_NAME,
- f'{MODULE_NAME}.models',
- f'{MODULE_NAME}.table_matcher',
- f'{MODULE_NAME}.table_structure'],
- package_data={'': ['en_ppstructure_mobile_v2_SLANet.onnx']},
- keywords=[
- 'ppstructure,table,rapidocr,rapid_table'
- ],
- classifiers=[
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: 3.8',
- 'Programming Language :: Python :: 3.9',
- 'Programming Language :: Python :: 3.10',
- ],
- entry_points={
- 'console_scripts': [f'{MODULE_NAME}={MODULE_NAME}.{MODULE_NAME}:main']
- }
-)
diff --git a/python/rapid_structure/test_images/layout.png b/python/rapid_structure/test_images/layout.png
deleted file mode 100644
index 29a1dc5..0000000
Binary files a/python/rapid_structure/test_images/layout.png and /dev/null differ
diff --git a/python/rapid_structure/test_images/table.jpg b/python/rapid_structure/test_images/table.jpg
deleted file mode 100644
index 95fdf84..0000000
Binary files a/python/rapid_structure/test_images/table.jpg and /dev/null differ
diff --git a/python/rapid_structure/tests/test_files/img_rot0_demo.jpg b/python/rapid_structure/tests/test_files/img_rot0_demo.jpg
deleted file mode 100644
index 412d419..0000000
Binary files a/python/rapid_structure/tests/test_files/img_rot0_demo.jpg and /dev/null differ
diff --git a/python/rapid_structure/tests/test_files/img_rot180_demo.jpg b/python/rapid_structure/tests/test_files/img_rot180_demo.jpg
deleted file mode 100644
index f4725b9..0000000
Binary files a/python/rapid_structure/tests/test_files/img_rot180_demo.jpg and /dev/null differ
diff --git a/python/rapid_structure/tests/test_layout.py b/python/rapid_structure/tests/test_layout.py
deleted file mode 100644
index 757c427..0000000
--- a/python/rapid_structure/tests/test_layout.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-import sys
-from pathlib import Path
-
-import cv2
-
-root_dir = Path(__file__).resolve().parent.parent
-
-sys.path.append(str(root_dir))
-
-from rapid_layout import RapidLayout
-
-
-def test_layout():
- img_path = str(root_dir / 'test_images' / 'layout.png')
- img = cv2.imread(img_path)
-
- layout_engine = RapidLayout()
-
- layout_res, elapse = layout_engine(img)
-
- assert len(layout_res) == 13
diff --git a/python/rapid_structure/tests/test_orientation.py b/python/rapid_structure/tests/test_orientation.py
deleted file mode 100644
index f1c1dca..0000000
--- a/python/rapid_structure/tests/test_orientation.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-import sys
-from pathlib import Path
-
-import cv2
-import pytest
-
-root_dir = Path(__file__).resolve().parent
-sys.path.append(str(root_dir.parent))
-
-from rapid_orientation import RapidOrientation
-text_orientation = RapidOrientation()
-
-
-@pytest.mark.parametrize(
- 'img_path, result',
- [
- (f'{root_dir}/test_files/img_rot0_demo.jpg', '0'),
- (f'{root_dir}/test_files/img_rot180_demo.jpg', '180'),
- ]
-)
-def test_img(img_path, result):
- img = cv2.imread(str(img_path))
- pred_result, _ = text_orientation(img)
-
- assert pred_result == result
diff --git a/python/rapid_structure/tests/test_table.py b/python/rapid_structure/tests/test_table.py
deleted file mode 100644
index a73e203..0000000
--- a/python/rapid_structure/tests/test_table.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Author: SWHL
-# @Contact: liekkaskono@163.com
-import sys
-from pathlib import Path
-
-import cv2
-
-root_dir = Path(__file__).resolve().parent.parent
-
-sys.path.append(str(root_dir))
-
-from rapid_table import RapidTable
-
-
-def test_table():
- img_path = str(root_dir / 'test_images' / 'table.jpg')
- img = cv2.imread(img_path)
-
- rapid_table = RapidTable()
-
- table_html_str, elapse = rapid_table(img)
- assert table_html_str.count('') == 16