Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions .github/workflows/lineless_table_rec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,7 @@ jobs:
run: |
pip install -r requirements.txt
pip install pytest

wget https://github.com/RapidAI/TableStructureRec/releases/download/v0.0.0/lineless_table_rec_models.zip
unzip lineless_table_rec_models.zip
mv lineless_table_rec_models/*.onnx lineless_table_rec/models/

pip install rapidocr
pytest tests/test_lineless_table_rec.py

GenerateWHL_PushPyPi:
Expand All @@ -54,11 +50,7 @@ jobs:
pip install -r requirements.txt
python -m pip install --upgrade pip
pip install wheel get_pypi_latest_version

wget https://github.com/RapidAI/TableStructureRec/releases/download/v0.0.0/lineless_table_rec_models.zip
unzip lineless_table_rec_models.zip
mv lineless_table_rec_models/*.onnx lineless_table_rec/models/

pip install rapidocr
python setup_lineless.py bdist_wheel "${{ github.ref_name }}"

# - name: Publish distribution 📦 to Test PyPI
Expand Down
8 changes: 0 additions & 8 deletions .github/workflows/table_cls.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ jobs:
pip install -r requirements.txt
pip install pytest beautifulsoup4

wget https://github.com/RapidAI/TableStructureRec/releases/download/v0.0.0/table_cls_models.zip
unzip table_cls_models.zip
mv table_cls_models/*.onnx table_cls/models/

pytest tests/test_table_cls.py

GenerateWHL_PushPyPi:
Expand All @@ -54,10 +50,6 @@ jobs:
python -m pip install --upgrade pip
pip install wheel get_pypi_latest_version

wget https://github.com/RapidAI/TableStructureRec/releases/download/v0.0.0/table_cls_models.zip
unzip table_cls_models.zip
mv table_cls_models/*.onnx table_cls/models/

python setup_table_cls.py bdist_wheel "${{ github.ref_name }}"

- name: Publish distribution 📦 to PyPI
Expand Down
12 changes: 2 additions & 10 deletions .github/workflows/wired_table_rec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ jobs:
run: |
pip install -r requirements.txt
pip install pytest beautifulsoup4

wget https://github.com/RapidAI/TableStructureRec/releases/download/v0.0.0/wired_table_rec_models.zip
unzip wired_table_rec_models.zip
mv wired_table_rec_models/*.onnx wired_table_rec/models/

pip install rapidocr
pytest tests/test_wired_table_rec.py

GenerateWHL_PushPyPi:
Expand All @@ -53,11 +49,7 @@ jobs:
pip install -r requirements.txt
python -m pip install --upgrade pip
pip install wheel get_pypi_latest_version

wget https://github.com/RapidAI/TableStructureRec/releases/download/v0.0.0/wired_table_rec_models.zip
unzip wired_table_rec_models.zip
mv wired_table_rec_models/*.onnx wired_table_rec/models/

pip install rapidocr
python setup_wired.py bdist_wheel "${{ github.ref_name }}"

- name: Publish distribution 📦 to PyPI
Expand Down
196 changes: 130 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@
</div>

### 最近更新
- **2024.11.22**
- 支持单字符匹配方案,需要RapidOCR>=1.4.0
- **2024.12.25**
- 补充文档扭曲矫正/去模糊/去阴影/二值化方案,可作为前置处理 [RapidUnDistort](https://github.com/Joker1212/RapidUnWrap)
- **2025.1.9**
- RapidTable支持了 unitable 模型,精度更高支持torch推理,补充测评数据
- RapidTable支持了 unitable 模型,精度更高支持torch推理,补充测评数据
- **2025.3.30**
- 输入输出格式对齐RapidTable
- 支持模型自动下载
- 增加来自paddle的新表格分类模型
- 增加最新PaddleX表格识别模型测评值
- 支持 rapidocr 2.0 取消重复ocr检测

### 简介
💖该仓库是用来对文档中表格做结构化识别的推理库,包括来自阿里读光有线和无线表格识别模型,llaipython(微信)贡献的有线表格模型,网易Qanything内置表格分类模型等。\
Expand Down Expand Up @@ -54,18 +58,19 @@
Surya-Tabled 使用内置ocr模块,表格模型为行列识别模型,无法识别单元格合并,导致分数较低

| 方法 | TEDS | TEDS-only-structure |
|:---------------------------------------------------------------------------------------------------------|:-----------:|:-------------------:|
| [surya-tabled(--skip-detect)](https://github.com/VikParuchuri/tabled) | 0.33437 | 0.65865 |
| [surya-tabled](https://github.com/VikParuchuri/tabled) | 0.33940 | 0.67103 |
| [deepdoctection(table-transformer)](https://github.com/deepdoctection/deepdoctection?tab=readme-ov-file) | 0.59975 | 0.69918 |
| [ppstructure_table_master](https://github.com/PaddlePaddle/PaddleOCR/tree/main/ppstructure) | 0.61606 | 0.73892 |
| [ppsturcture_table_engine](https://github.com/PaddlePaddle/PaddleOCR/tree/main/ppstructure) | 0.67924 | 0.78653 |
| [StructEqTable](https://github.com/UniModal4Reasoning/StructEqTable-Deploy) | 0.67310 | 0.81210 |
| [RapidTable(SLANet)](https://github.com/RapidAI/RapidTable) | 0.71654 | 0.81067 |
| table_cls + wired_table_rec v1 + lineless_table_rec | 0.75288 | 0.82574 |
| table_cls + wired_table_rec v2 + lineless_table_rec | 0.77676 | 0.84580 |
| [RapidTable(SLANet-plus)](https://github.com/RapidAI/RapidTable) | 0.84481 | 0.91369 |
| [RapidTable(unitable)](https://github.com/RapidAI/RapidTable) | **0.86200** | **0.91813** |
|:---------------------------------------------------------------------------------------------------------|:-----------:|:-----------------:|
| [surya-tabled(--skip-detect)](https://github.com/VikParuchuri/tabled) | 0.33437 | 0.65865 |
| [surya-tabled](https://github.com/VikParuchuri/tabled) | 0.33940 | 0.67103 |
| [deepdoctection(table-transformer)](https://github.com/deepdoctection/deepdoctection?tab=readme-ov-file) | 0.59975 | 0.69918 |
| [ppstructure_table_master](https://github.com/PaddlePaddle/PaddleOCR/tree/main/ppstructure) | 0.61606 | 0.73892 |
| [ppsturcture_table_engine](https://github.com/PaddlePaddle/PaddleOCR/tree/main/ppstructure) | 0.67924 | 0.78653 |
| [StructEqTable](https://github.com/UniModal4Reasoning/StructEqTable-Deploy) | 0.67310 | 0.81210 |
| [RapidTable(SLANet)](https://github.com/RapidAI/RapidTable) | 0.71654 | 0.81067 |
| table_cls + wired_table_rec v1 + lineless_table_rec | 0.75288 | 0.82574 |
| table_cls + wired_table_rec v2 + lineless_table_rec | 0.77676 | 0.84580 |
| [PaddleX(SLANetXt+RT-DERT)](https://github.com/PaddlePaddle/PaddleX) | 0.79900 | **0.92222** |
| [RapidTable(SLANet-plus)](https://github.com/RapidAI/RapidTable) | 0.84481 | 0.91369 |
| [RapidTable(unitable)](https://github.com/RapidAI/RapidTable) | **0.86200** | 0.91813 |

### 使用建议
wired_table_rec_v2(有线表格精度最高): 通用场景有线表格(论文,杂志,期刊, 收据,单据,账单)
Expand All @@ -75,63 +80,93 @@ wired_table_rec_v2 对1500px内大小的图片效果最好,所以分辨率超
SLANet-plus/unitable (综合精度最高): 文档场景表格(论文,杂志,期刊中的表格)

### 安装

rapidocr2.0以上版本支持torch,onnx,paddle,openvino等多引擎切换,详情参考[rapidocr文档](https://rapidai.github.io/RapidOCRDocs/main/install_usage/rapidocr/usage/)
``` python {linenos=table}
pip install wired_table_rec lineless_table_rec table_cls
pip install rapidocr
```

### 快速使用

> ⚠️注意:在`wired_table_rec/table_cls`>=1.2.0` `lineless_table_rec` > 0.1.0 后,采用同RapidTable完全一致格式的输入输出
``` python {linenos=table}
import os
from pathlib import Path

from lineless_table_rec import LinelessTableRecognition
from lineless_table_rec.utils_table_recover import format_html, plot_rec_box_with_logic_info, plot_rec_box
from wired_table_rec.utils.utils import VisTable
from table_cls import TableCls
from wired_table_rec import WiredTableRecognition
from rapidocr_onnxruntime import RapidOCR

lineless_engine = LinelessTableRecognition()
wired_engine = WiredTableRecognition()
# 默认小yolo模型(0.1s),可切换为精度更高yolox(0.25s),更快的qanything(0.07s)模型
table_cls = TableCls() # TableCls(model_type="yolox"),TableCls(model_type="q")
img_path = f'images/img14.jpg'

cls,elasp = table_cls(img_path)
if cls == 'wired':
table_engine = wired_engine
else:
table_engine = lineless_engine

html, elasp, polygons, logic_points, ocr_res = table_engine(img_path)
print(f"elasp: {elasp}")

# 使用其他ocr模型
#ocr_engine =RapidOCR(det_model_path="xxx/det_server_infer.onnx",rec_model_path="xxx/rec_server_infer.onnx")
#ocr_res, _ = ocr_engine(img_path)
#html, elasp, polygons, logic_points, ocr_res = table_engine(img_path, ocr_result=ocr_res)
# output_dir = f'outputs'
# complete_html = format_html(html)
# os.makedirs(os.path.dirname(f"{output_dir}/table.html"), exist_ok=True)
# with open(f"{output_dir}/table.html", "w", encoding="utf-8") as file:
# file.write(complete_html)
# # 可视化表格识别框 + 逻辑行列信息
# plot_rec_box_with_logic_info(
# img_path, f"{output_dir}/table_rec_box.jpg", logic_points, polygons
# )
# # 可视化 ocr 识别框
# plot_rec_box(img_path, f"{output_dir}/ocr_box.jpg", ocr_res)
from wired_table_rec.main import WiredTableInput, WiredTableRecognition
from lineless_table_rec.main import LinelessTableInput, LinelessTableRecognition
from rapidocr import RapidOCR


if __name__ == "__main__":
# Init
wired_input = WiredTableInput()
lineless_input = LinelessTableInput()
wired_engine = WiredTableRecognition(wired_input)
lineless_engine = LinelessTableRecognition(lineless_input)
viser = VisTable()
# 默认小yolo模型(0.1s),可切换为精度更高yolox(0.25s),更快的qanything(0.07s)模型或paddle模型(0.03s)
table_cls = TableCls()
img_path = f"tests/test_files/table.jpg"

cls, elasp = table_cls(img_path)
if cls == "wired":
table_engine = wired_engine
else:
table_engine = lineless_engine

# 使用RapidOCR输入
ocr_engine = RapidOCR()
rapid_ocr_output = ocr_engine(img_path, return_word_box=True)
ocr_result = list(
zip(rapid_ocr_output.boxes, rapid_ocr_output.txts, rapid_ocr_output.scores)
)
table_results = table_engine(
img_path, ocr_result=ocr_result
)

# 使用单字识别
# word_results = rapid_ocr_output.word_results
# ocr_result = [
# [word_result[2], word_result[0], word_result[1]] for word_result in word_results
# ]
# table_results = table_engine(
# img_path, ocr_result=ocr_result, enhance_box_line=False
# )

# Save
# save_dir = Path("outputs")
# save_dir.mkdir(parents=True, exist_ok=True)
#
# save_html_path = f"outputs/{Path(img_path).stem}.html"
# save_drawed_path = f"outputs/{Path(img_path).stem}_table_vis{Path(img_path).suffix}"
# save_logic_path = (
# f"outputs/{Path(img_path).stem}_table_vis_logic{Path(img_path).suffix}"
# )

# Visualize table rec result
# vis_imged = viser(
# img_path, table_results, save_html_path, save_drawed_path, save_logic_path
# )





```

#### 单字ocr匹配

```python
# 将单字box转换为行识别同样的结构)
from rapidocr_onnxruntime import RapidOCR
from wired_table_rec.utils_table_recover import trans_char_ocr_res
from rapidocr import RapidOCR
img_path = "tests/test_files/wired/table4.jpg"
ocr_engine =RapidOCR()
ocr_res, _ = ocr_engine(img_path, return_word_box=True)
ocr_res = trans_char_ocr_res(ocr_res)
ocr_engine = RapidOCR()
rapid_ocr_output = ocr_engine(img_path, return_word_box=True)
word_results = rapid_ocr_output.word_results
ocr_result = [
[word_result[2], word_result[0], word_result[1]] for word_result in word_results
]
```

#### 表格旋转及透视修正
Expand Down Expand Up @@ -177,24 +212,53 @@ for i, res in enumerate(result):

### 核心参数
```python
wired_table_rec = WiredTableRecognition()
html, elasp, polygons, logic_points, ocr_res = wired_table_rec(
# 输入(WiredTableInput/LinelessTableInput)
@dataclass
class WiredTableInput:
model_type: Optional[str] = "unet" #unet/cycle_center_net
model_path: Union[str, Path, None, Dict[str, str]] = None
use_cuda: bool = False
device: str = "cpu"

@dataclass
class LinelessTableInput:
model_type: Optional[str] = "lore" #lore
model_path: Union[str, Path, None, Dict[str, str]] = None
use_cuda: bool = False
device: str = "cpu"

# 输出(WiredTableOutput/LinelessTableOutput)
@dataclass
class WiredTableOutput:
pred_html: Optional[str] = None
cell_bboxes: Optional[np.ndarray] = None
logic_points: Optional[np.ndarray] = None
elapse: Optional[float] = None

@dataclass
class LinelessTableOutput:
pred_html: Optional[str] = None
cell_bboxes: Optional[np.ndarray] = None
logic_points: Optional[np.ndarray] = None
elapse: Optional[float] = None
```

```python
wired_table_rec = WiredTableRecognition(WiredTableInput())
table_results = wired_table_rec(
img, # 图片 Union[str, np.ndarray, bytes, Path, PIL.Image.Image]
ocr_result, # 输入rapidOCR识别结果,不传默认使用内部rapidocr模型
version="v2", #默认使用v2线框模型,切换阿里读光模型可改为v1
enhance_box_line=True, # 识别框切割增强(关闭避免多余切割,开启减少漏切割),默认为True
col_threshold=15, # 识别框左边界x坐标差值小于col_threshold的默认同列
row_threshold=10, # 识别框上边界y坐标差值小于row_threshold的默认同行
rotated_fix=True, # wiredV2支持,轻度旋转(-45°~45°)矫正,默认为True
need_ocr=True, # 是否进行OCR识别, 默认为True
rec_again=True,# 是否针对未识别到文字的表格框,进行单独截取再识别,默认为True
)
lineless_table_rec = LinelessTableRecognition()
html, elasp, polygons, logic_points, ocr_res = lineless_table_rec(
lineless_table_rec = LinelessTableRecognition(LinelessTableInput())
table_results = lineless_table_rec(
img, # 图片 Union[str, np.ndarray, bytes, Path, PIL.Image.Image]
ocr_result, # 输入rapidOCR识别结果,不传默认使用内部rapidocr模型
need_ocr=True, # 是否进行OCR识别, 默认为True
rec_again=True,# 是否针对未识别到文字的表格框,进行单独截取再识别,默认为True
)
```

Expand Down Expand Up @@ -225,7 +289,7 @@ html, elasp, polygons, logic_points, ocr_res = lineless_table_rec(
```mermaid
flowchart TD
A[/表格图片/] --> B([表格分类 table_cls])
B --> C([有线表格识别 wired_table_rec]) & D([无线表格识别 lineless_table_rec]) --> E([文字识别 rapidocr_onnxruntime])
B --> C([有线表格识别 wired_table_rec]) & D([无线表格识别 lineless_table_rec]) --> E([文字识别 rapidocr])
E --> F[/html结构化输出/]
```

Expand Down
Loading