# 🔍 OCR 可视化验证系统

一个功能强大的 OCR 识别与验证系统，集成了多种 OCR 工具支持、智能交叉验证、可视化校验和表格数据分析功能，专为财务报表、数据表格等复杂文档设计。

## ✨ 核心功能

### 🎯 多工具 OCR 支持
- **Dots OCR**：专业 VLM OCR 引擎
- **PaddleOCR PPStructV3**：结构化文档识别
- **Table Recognition V2**：专业表格识别
- **MinerU VLM-2.5.3**：多模态文档理解

### 🔄 智能交叉验证
- **多数据源对比**：支持不同 OCR 工具结果的交叉验证
- **细粒度差异检测**：精确到单元格级别的差异分析
- **智能表格对比**：
  - 标准表格模式
  - 流水表格模式（支持表头位置检测）
- **差异分类统计**：
  - 金额差异（`table_amount`）
  - 日期时间差异（`table_datetime`）
  - 文本差异（`table_text`）
  - 表头差异（位置、内容、结构）
  - 段落差异

### 📊 可视化校验工具
- **交互式图像标注**：点击文本高亮对应图像位置
- **精确坐标定位**：基于 bbox 的精确位置标示
- **旋转角度处理**：
  - 自动检测文档旋转角度
  - 支持手动调整旋转
  - 智能坐标转换
- **多渲染模式**：
  - HTML 渲染（支持横向滚动）
  - Markdown 渲染
  - DataFrame 表格
  - 原始文本

### 📈 表格数据分析
- **智能表格解析**：自动识别并转换 HTML 表格
- **交互式操作**：
  - 过滤（按列值、关键词）
  - 排序（升序/降序）
  - 分页显示
  - 列选择显示
- **数据导出**：支持 CSV、Excel 格式
- **统计分析**：自动生成数值列统计信息

### 🔧 数字标准化
- 全角/半角字符转换
- 千分位分隔符标准化
- 小数点格式统一
- 支持批量标准化处理

## 🚀 快速开始

### 环境配置

```bash
# 创建 conda 环境
conda create -n py312 python=3.12 -y
conda activate py312

# 克隆项目
git clone https://gitee.com/zhch158_admin/ocr_verify.git
cd ocr_verify

# 安装依赖
pip install -r requirements.txt
# 或手动安装
pip install streamlit plotly pandas pillow numpy opencv-python openpyxl \
    beautifulsoup4 pyyaml fuzzywuzzy python-Levenshtein
```

### 配置文件

编辑 [`config.yaml`](config.yaml) 配置数据源：

```yaml
data_sources:
  - name: "至远彩色_2023年报"
    ocr_tool: "ppstructv3"
    ocr_out_dir: "/path/to/ppstructv3/output"
    src_img_dir: "/path/to/source/images"
    description: "使用 PPStructV3 的识别结果"
  
  - name: "至远彩色_2023年报"
    ocr_tool: "mineru"
    ocr_out_dir: "/path/to/mineru/output"
    src_img_dir: "/path/to/source/images"
    description: "使用 MinerU 的识别结果"
```

## 📖 使用指南

### 1️⃣ 启动可视化验证工具

```bash
# 启动 Streamlit 应用
python -m streamlit run streamlit_ocr_validator.py

# 或使用启动脚本
python run_streamlit_validator.py
```

**功能模块：**

#### 📄 内容人工检查
- 选择数据源和页码
- 点击文本内容查看图像位置
- 旋转图像调整角度
- 显示所有文本框或仅显示选中框

#### 🔍 交叉验证结果
- 选择两个不同的 OCR 数据源
- 点击「交叉验证」按钮运行批量验证
- 查看详细的差异对比结果
- 下载验证报告（Excel、JSON）

#### 📊 表格分析
- 解析 HTML 表格为 DataFrame
- 过滤、排序、搜索表格数据
- 导出表格为 CSV 或 Excel
- 查看统计信息

### 2️⃣ 命令行对比工具

使用 [`compare_ocr_results.py`](compare_ocr_results.py) 进行命令行对比：

```bash
# 基本对比
python compare_ocr_results.py file1.md file2.md

# 使用流水表格模式
python compare_ocr_results.py file1.md file2.md \
    --table-mode flow_list \
    --similarity-algorithm ratio \
    -o output/comparison_result \
    -f both

# 仅生成 JSON 报告
python compare_ocr_results.py file1.md file2.md \
    -f json -o report
```

**参数说明：**
- `-o, --output`：输出文件名（不含扩展名）
- `-f, --format`：输出格式（`json`、`markdown`、`both`）
- `--table-mode`：表格比对模式（`standard`、`flow_list`）
- `--similarity-algorithm`：相似度算法（`ratio`、`partial_ratio`、`token_sort_ratio`、`token_set_ratio`）
- `--ignore-images`：忽略图片内容对比

### 3️⃣ 数字标准化工具

使用 [`normalize_financial_numbers.py`](normalize_financial_numbers.py)：

```python
from normalize_financial_numbers import normalize_financial_numbers, normalize_json_file

# 标准化文本中的数字
text = "２０２３年净利润为２８，２３９，３０５．４８元"
normalized = normalize_financial_numbers(text)
# 输出: "2023年净利润为28,239,305.48元"

# 批量标准化 JSON 文件
normalize_json_file("input.json", "output.json")
```

## 📁 项目结构

```
ocr_verify/
├── streamlit_ocr_validator.py          # 主应用入口
├── streamlit_validator_core.py         # 核心验证器类
├── streamlit_validator_ui.py           # UI 组件
├── streamlit_validator_table.py        # 表格处理
├── streamlit_validator_cross.py        # 交叉验证
├── streamlit_validator_result.py       # 结果展示
├── ocr_validator_layout.py             # 布局管理
├── ocr_validator_utils.py              # 工具函数
├── ocr_validator_file_utils.py         # 文件处理
├── compare_ocr_results.py              # OCR 结果对比
├── normalize_financial_numbers.py      # 数字标准化
├── merge_mineru_paddle_ocr.py          # 合并 MinerU 和 Paddle OCR 结果
├── config.yaml                         # 配置文件
├── styles.css                          # 样式文件
├── output/                             # 输出目录
│   └── pre_validation/                 # 交叉验证结果
├── .streamlit/                         # Streamlit 配置
│   └── config.toml                     # Streamlit 设置
└── README.md                           # 项目文档
```

## 🎯 核心功能详解

### 交叉验证流程

1. **数据源选择**
   - 选择 OCR 数据源（如 PPStructV3）
   - 选择验证数据源（如 MinerU）

2. **批量验证**
   - 自动匹配相同页码的文件
   - 逐页进行差异检测
   - 生成详细验证报告

3. **差异分析**
   - 表格差异：逐单元格对比
   - 段落差异：智能段落匹配
   - 结构差异：表头位置、行缺失等

4. **结果展示**
   - 差异列表（按类型、严重程度分类）
   - 统计图表（饼图、柱状图）
   - 详细对比视图（左右对照）

### 表格对比算法

#### 标准模式 (`standard`)
- 适用于结构固定的表格
- 逐行逐列对比
- 适合财务报表、数据统计表

#### 流水表格模式 (`flow_list`)
- 智能检测表头位置
- 支持表头前内容对比
- 自动列类型检测（数字、日期、文本）
- 适合银行流水、交易记录等

### 图像旋转处理

```python
# 自动检测旋转角度
detection_result = detect_image_orientation_by_opencv(image_path)

# 手动调整旋转
validator.layout_manager.rotated_angle = 90  # 顺时针 90 度

# 坐标自动转换
rotated_image, rotated_bboxes = rotate_image_and_coordinates(
    image, angle, coordinates_list, rotate_coordinates=True
)
```

## 📊 输出示例

### 交叉验证报告

#### JSON 格式
```json
{
  "differences": [
    {
      "type": "table_amount",
      "position": "第15行第5列",
      "file1_value": "15.00",
      "file2_value": "15,00",
      "description": "金额不一致: 15.00 vs 15,00",
      "severity": "medium",
      "column_name": "金额",
      "column_type": "numeric"
    }
  ],
  "statistics": {
    "total_differences": 42,
    "table_differences": 35,
    "amount_differences": 8,
    "datetime_differences": 3,
    "text_differences": 24,
    "paragraph_differences": 7,
    "high_severity": 8,
    "medium_severity": 20,
    "low_severity": 14
  }
}
```

#### Markdown 格式
```markdown
# OCR结果对比报告

## 统计信息
- 总差异数量: **42**
- 表格差异: **35**
  - 金额差异: **8**
  - 日期差异: **3**
  - 文本差异: **24**
- 段落差异: **7**

## 差异详情
| 序号 | 位置 | 类型 | 原OCR结果 | 验证结果 | 描述 |
|------|------|------|-----------|----------|------|
| 1 | 第15行第5列 | table_amount | 15.00 | 15,00 | 金额不一致 |
```

## 🔧 高级配置

### OCR 工具配置

在 [`config.yaml`](config.yaml) 中配置工具参数：

```yaml
ocr:
  tools:
    ppstructv3:
      name: "PPStructV3"
      json_structure: "object"
      rotation:
        coordinates_are_pre_rotated: true
    
    mineru:
      name: "MinerU"
      json_structure: "array"
      rotation:
        coordinates_are_pre_rotated: false
```

### 合并 MinerU 和 Paddle OCR 结果
```bash
echo "A用户_单元格扫描流水"
python merge_mineru_paddle_ocr.py \
  --mineru-dir "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/mineru-vlm-2.5.3_Results" \
  --paddle-dir "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/data_PPStructureV3_Results" \
  --output-dir "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/merged_results" \
  --format "both"

echo "B用户_扫描流水"
python merge_mineru_paddle_ocr.py \
  --mineru-dir "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/mineru-vlm-2.5.3_Results" \
  --paddle-dir "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/data_PPStructureV3_Results" \
  --output-dir "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/merged_results" \
  --format "both"

echo "德_内蒙古银行照"
python merge_mineru_paddle_ocr.py \
  --mineru-dir "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/mineru-vlm-2.5.3_Results" \
  --paddle-dir "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/data_PPStructureV3_Results" \
  --output-dir "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/merged_results" \
  --format "both"

echo "对公_招商银行图"
python merge_mineru_paddle_ocr.py \
  --mineru-dir "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/mineru-vlm-2.5.3_Results" \
  --paddle-dir "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/data_PPStructureV3_Results" \
  --output-dir "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/merged_results" \
  --format "both"

echo "至远彩色印刷工业有限公司"
python merge_mineru_paddle_ocr.py \
  --mineru-dir "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/mineru-vlm-2.5.3_Results" \
  --paddle-dir "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/data_PPStructureV3_Results" \
  --output-dir "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/merged_results" \
  --format "both"


```

### Streamlit 配置

编辑 [`.streamlit/config.toml`](.streamlit/config.toml)：

```toml
[theme]
primaryColor = "#0288d1"
backgroundColor = "#ffffff"
secondaryBackgroundColor = "#f5f5f5"

[server]
maxUploadSize = 200
enableXsrfProtection = true
```

## 🐛 常见问题

### Q1: 图像显示位置不正确？
**A:** 检查 OCR 工具的坐标是否已预旋转，在 `config.yaml` 中调整 `coordinates_are_pre_rotated` 设置。

### Q2: 交叉验证结果为空？
**A:** 确保两个数据源包含相同页码的文件，且文件名格式为 `*_page_XXX.json`。

### Q3: 表格对比差异过多？
**A:** 尝试切换到 `flow_list` 模式，或调整相似度算法参数。

## 📝 开发说明

### 扩展开发
- 新增 OCR 工具：在 `ocr_validator_utils.py` 中添加解析函数
- 自定义对比算法：继承 `OCRResultComparator` 类
- 新增渲染模式：在 `ocr_validator_layout.py` 中扩展

## 🤝 贡献指南

欢迎提交 Issue 和 Pull Request！

1. Fork 本仓库
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 提交 Pull Request

## 📄 许可证

本项目采用 MIT 许可证。详见 [LICENSE](LICENSE) 文件。

## 📞 联系方式

- **作者**: zhch158_admin
- **邮箱**: zhch158@sina.com
- **仓库**: https://gitee.com/zhch158_admin/ocr_verify.git

## 🙏 致谢

---

**最后更新**: 2025年10月10日