MinerU产品体验
介绍
MinerU 可以把 PDF 转成 markdown/json 文件,支持提取 Table、Image、LaTex 公式,能保证 text、Image 等片段的顺序,适合为下游模型提供高质量的文档数据。
MinerU 是一个基于 PDF-Extract-Kit 项目的整合的产品,提供 Docker 部署、API 服务、命令行工具等产品能力。
官方的产品口号就是 “MinerU 一站式开源数据提取工具”。
地址
体验地址 https://huggingface.co/spaces/opendatalab/MinerU
arXiv 地址 https://arxiv.org/abs/2409.18839
产品特性
MinerU 产品的功能特性选项:
- Layout Model:可以选择 doclayout_yolo、layoutlmv3
- Language:做 OCR 时指定的语言
- LaTex 识别:可选项
- Table 识别:可选项
MinerU 项目依赖
从致谢列表看 MinerU 的项目依赖。由于项目依赖 ultralytics 和 PyMuPDF,它们的开源协议 AGPL-3.0 具有传染性,因此 MinerU 也是 AGPL-3.0 协议。
注意:如果 Layout 模型包括 LayoutLMv3,它是 CC BY-NC-SA 4.0 非商用模型。
项目 | 说明 | 开源协议 |
---|---|---|
PDF-Extract-Kit | MinerU 实际底层使用的工具 | AGPL-3.0 |
DocLayout-YOLO | Layout 分析模型,来自 opendatalab | AGPL-3.0 |
StructEqTable | Table 识别和解析模型 | Apache 2.0 |
RapidTable | Table 识别和解析模型 | |
PaddleOCR | Paddle OCR | Apache 2.0 |
PyMuPDF | pdf 解析库 | AGPL-3.0 |
layoutreader | 基于 LayoutLMv3 的 LayoutReader Model,排序 bboxes | |
fast-langdetect | ||
pdfminer.six |
PDF-Extract-Kit 项目依赖
PDF-Extrac-Kit 的项目依赖,同样由于依赖 ultralytics 项目,因此是 AGPL-3.0 协议
项目 | 说明 | 开源协议 |
---|---|---|
LayoutLMv3 | Layout 分析模型,来自 Microsoft | CC BY-NC-SA 4.0 |
UniMERNet | 数学公式识别模型,来自 opendatalab | Apache 2.0 |
StructEqTable | Table 识别和解析模型 | Apache 2.0 |
YOLO | 公式识别模型。来自 ultralytics | AGPL-3.0, Enterprise |
PaddleOCR | Paddle OCR | Apache 2.0 |
DocLayout-YOLO | YOLO Layout 分析模型,来自 opendatalab | AGPL-3.0 |
DocLayout-YOLO 项目
DocLayout-YOLO 是基于 YOLO-v10 的模型(存疑),code 项目里使用了 untralytics。
模型大小才 40MB,本地 CPU 推理也无压力。
体验举例如下,它可以分析、合并、排序 segment
使用 doclayout 的推理代码,很容易就能在本地跑起来
import cv2
from doclayout_yolo import YOLOv10
# Load the pre-trained model
model = YOLOv10("path/to/provided/model")
# Perform prediction
det_res = model.predict(
"path/to/image", # Image to predict
imgsz=1024, # Prediction image size
conf=0.2, # Confidence threshold
device="cuda:0" # Device to use (e.g., 'cuda:0' or 'cpu')
)
# Annotate and save the result
annotated_frame = det_res[0].plot(pil=True, line_width=5, font_size=20)
cv2.imwrite("result.jpg", annotated_frame)
模型推理结果是 segment 的 bbox
>>> json.loads(det_res[0].tojson())
[{'name': 'plain text', 'class': 1, 'confidence': 0.98255, 'box': {'x1': 147.49417, 'y1': 1143.02441, 'x2': 780.48468, 'y2': 1651.43872}}, {'name': 'plain text', 'class': 1, 'confidence': 0.97484, 'box': {'x1': 836.45563, 'y1': 1572.29236, 'x2': 1471.37744, 'y2': 1759.40247}}, {'name': 'plain text', 'class': 1, 'confidence': 0.97245, 'box': {'x1': 836.82758, 'y1': 1000.12469, 'x2': 1470.98572, 'y2': 1286.46387}}, {'name': 'plain text', 'class': 1, 'confidence': 0.97183, 'box': {'x1': 147.16068, 'y1': 1668.2688, 'x2': 781.2616, 'y2': 1759.5813}}, {'name': 'plain text', 'class': 1, 'confidence': 0.96726, 'box': {'x1': 146.82661, 'y1': 1000.60315, 'x2': 780.53552, 'y2': 1126.9834}}, {'name': 'plain text', 'class': 1, 'confidence': 0.95219, 'box': {'x1': 836.68713, 'y1': 1302.34619, 'x2': 1470.69482, 'y2': 1556.82751}}, {'name': 'figure', 'class': 3, 'confidence': 0.87933, 'box': {'x1': 185.84866, 'y1': 81.46348, 'x2': 424.53577, 'y2': 260.80255}}, {'name': 'figure_caption', 'class': 4, 'confidence': 0.83036, 'box': {'x1': 156.52231, 'y1': 34.28653, 'x2': 460.18802, 'y2': 58.10561}}, {'name': 'figure_caption', 'class': 4, 'confidence': 0.82028, 'box': {'x1': 149.40076, 'y1': 338.31763, 'x2': 332.39313, 'y2': 356.38214}}, {'name': 'title', 'class': 0, 'confidence': 0.80577, 'box': {'x1': 859.20679, 'y1': 367.29861, 'x2': 1052.14221, 'y2': 386.68372}}, {'name': 'title', 'class': 0, 'confidence': 0.73404, 'box': {'x1': 476.59558, 'y1': 367.11325, 'x2': 825.5824, 'y2': 386.93414}}, {'name': 'title', 'class': 0, 'confidence': 0.72799, 'box': {'x1': 858.33521, 'y1': 28.94449, 'x2': 1054.80261, 'y2': 49.44512}}, {'name': 'title', 'class': 0, 'confidence': 0.70039, 'box': {'x1': 854.1405, 'y1': 54.6973, 'x2': 1201.36023, 'y2': 71.83387}}, {'name': 'title', 'class': 0, 'confidence': 0.68144, 'box': {'x1': 148.31096, 'y1': 774.55481, 'x2': 202.76604, 'y2': 790.20837}}, {'name': 'figure', 'class': 3, 'confidence': 0.67492, 'box': {'x1': 142.1284, 'y1': 6.74782, 'x2': 1465.22485, 'y2': 840.65063}}, {'name': 'plain text', 'class': 1, 'confidence': 0.65931, 'box': {'x1': 855.38391, 'y1': 74.03815, 'x2': 1465.38708, 'y2': 125.86041}}, {'name': 'plain text', 'class': 1, 'confidence': 0.64421, 'box': {'x1': 147.82094, 'y1': 792.07416, 'x2': 416.98972, 'y2': 809.37012}}, {'name': 'title', 'class': 0, 'confidence': 0.62825, 'box': {'x1': 481.47455, 'y1': 30.73467, 'x2': 830.59497, 'y2': 51.26509}}, {'name': 'plain text', 'class': 1, 'confidence': 0.57245, 'box': {'x1': 147.33006, 'y1': 631.99005, 'x2': 469.26239, 'y2': 755.53864}}, {'name': 'figure_caption', 'class': 4, 'confidence': 0.54594, 'box': {'x1': 145.70325, 'y1': 865.39014, 'x2': 1470.43054, 'y2': 979.73633}}, {'name': 'plain text', 'class': 1, 'confidence': 0.49084, 'box': {'x1': 854.66876, 'y1': 150.25163, 'x2': 1448.45837, 'y2': 201.86794}}, {'name': 'plain text', 'class': 1, 'confidence': 0.44152, 'box': {'x1': 145.70325, 'y1': 865.39014, 'x2': 1470.43054, 'y2': 979.73633}}, {'name': 'figure_caption', 'class': 4, 'confidence': 0.40644, 'box': {'x1': 148.53265, 'y1': 284.1348, 'x2': 456.11798, 'y2': 321.22171}}, {'name': 'title', 'class': 0, 'confidence': 0.39748, 'box': {'x1': 148.58447, 'y1': 614.51422, 'x2': 210.47787, 'y2': 630.07043}}, {'name': 'title', 'class': 0, 'confidence': 0.38357, 'box': {'x1': 854.4386, 'y1': 208.39394, 'x2': 1201.28882, 'y2': 225.20853}}, {'name': 'plain text', 'class': 1, 'confidence': 0.37374, 'box': {'x1': 855.37506, 'y1': 412.58795, 'x2': 1463.5697, 'y2': 464.16812}}, {'name': 'plain text', 'class': 1, 'confidence': 0.36303, 'box': {'x1': 148.53265, 'y1': 284.1348, 'x2': 456.11798, 'y2': 321.22171}}, {'name': 'figure', 'class': 3, 'confidence': 0.36003, 'box': {'x1': 148.69635, 'y1': 422.41458, 'x2': 465.4986, 'y2': 585.81549}}, {'name': 'plain text', 'class': 1, 'confidence': 0.34239, 'box': {'x1': 474.00449, 'y1': 126.01015, 'x2': 840.97162, 'y2': 251.03653}}, {'name': 'plain text', 'class': 1, 'confidence': 0.31704, 'box': {'x1': 854.30182, 'y1': 231.28908, 'x2': 1433.1626, 'y2': 318.93518}}, {'name': 'title', 'class': 0, 'confidence': 0.27773, 'box': {'x1': 854.70093, 'y1': 129.86101, 'x2': 1157.01257, 'y2': 146.56113}}, {'name': 'plain text', 'class': 1, 'confidence': 0.23601, 'box': {'x1': 855.74359, 'y1': 485.03232, 'x2': 1460.28857, 'y2': 536.75861}}, {'name': 'figure_caption', 'class': 4, 'confidence': 0.20253, 'box': {'x1': 158.76968, 'y1': 377.00912, 'x2': 433.56165, 'y2': 399.53653}}]
有了 bbox,就可以标注到原图里,形成标注图 annotated_frame = det_res[0].plot(pil=True, line_width=5, font_size=20)
可以直接切图保存下来 det_res[0].save_crop('./')
% tree
.
├── abandon
│ └── im.jpg.jpg
├── doclayout_yolo_docstructbench_imgsz1024.pt
├── figure
│ ├── im.jpg.jpg
│ └── im.jpg2.jpg
├── figure_caption
│ ├── im.jpg.jpg
│ └── im.jpg2.jpg
├── plain\ text
│ ├── im.jpg.jpg
│ ├── im.jpg2.jpg
│ ├── im.jpg3.jpg
│ ├── im.jpg4.jpg
│ ├── im.jpg5.jpg
│ ├── im.jpg6.jpg
│ └── im.jpg7.jpg
├── result.jpg
Leave a Reply