发票与收据 OCR:关键字段定位与结构化提取

FreeGuideOnline 最新 2026-06-23

bash pip install paddleocr opencv-python

Tesseract 备用:

sudo apt install tesseract-ocr tesseract-ocr-chi-sim

pip install pytesseract


## 图像预处理

原始票据图像往往存在倾斜、噪声、阴影等问题,良好的预处理能显著提升 OCR 准确率。

### 关键步骤
1. **灰度化**:将彩色图像转为灰度,减少干扰。  
2. **二值化**:使用阈值(如 Otsu 算法)将图像变为黑白,增强文字轮廓。  
3. **倾斜校正**:通过霍夫变换检测文字行倾斜角度,旋转图像使其水平。  
4. **去噪**:中值滤波或形态学操作去除孤立噪点。  
5. **透视变换**:若图像拍摄角度不正,可检测票据边缘,矫正为正面视图。

### 代码片段(OpenCV)
```python
import cv2
img = cv2.imread('receipt.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Otsu 二值化
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 倾斜校正:使用最小外接矩形计算角度
coords = np.column_stack(np.where(binary > 0))
angle = cv2.minAreaRect(coords)[-1]
if angle < -45:
    angle = 90 + angle
(h, w) = binary.shape
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(binary, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)

OCR 识别与结果解析

使用 PaddleOCR 进行文本检测与识别

PaddleOCR 同时完成文本检测和识别,返回每行的文本和边界框坐标。

from paddleocr import PaddleOCR
ocr = PaddleOCR(use_angle_cls=True, lang='ch')
result = ocr.ocr('invoice.jpg', cls=True)
# result 是一个列表,每个元素为 [ [坐标], (文本, 置信度) ]

获取结构化信息

识别结果是一场“散乱”的文字行集合,我们需要从中提取字段值。

关键字段定位方法

方法一:基于关键词的相对位置

大多数票据字段前都有固定的提示词(如“发票代码:”)。我们可以:

  1. 遍历所有识别文本,找到包含关键词的行。
  2. 用该行的坐标信息,在附近区域(右侧或下方)寻找数值内容。
  3. 通过正则表达式验证数值格式(如 6-12 位数字、日期格式、金额格式等)。

示例伪代码

keyword = "发票代码"
for line in result:
    text = line[1][0]
    if keyword in text:
        # 在该行的右侧寻找数字
        # 可利用坐标筛选同行或下一行的文字
        target_boxes = find_right_or_below_boxes(keyword_box, result)
        for box in target_boxes:
            if re.match(r'^\d{10,12}$', box_text):
                invoice_code = box_text

方法二:基于版式规则的区域裁剪

对于版式固定的票据(如增值税专用发票),可直接按比例裁剪感兴趣区域(ROI)。比如发票代码总在右上角固定位置。但此方法泛化性较差,适用于内部系统或已知票据类型。

方法三:目标检测模型定位

当需要处理多种版式、任意拍照角度的票据时,采用深度学习方法是更健壮的选择。一般流程:

  1. 收集并标注票据图片,框出关键字段(如“发票代码”的文字区域和对应的值区域)。
  2. 训练目标检测模型(如 YOLOv5)检测所有字段的位置。
  3. 推理时,检测到字段位置后,直接送入 OCR 或对字段进行分类识别。

标注工具可使用 LabelImg(Pascal VOC 格式)或 labelme(JSON 格式)。虽然实施门槛较高,但生产环境中往往使用此方案。

结构化输出与后处理

提取到原始字段文本后,需要格式化和验证。

数据清洗

  • 去除多余空格、特殊字符。
  • 日期格式统一:如“2023年01月01日”转换为“2023-01-01”。
  • 金额处理:处理中文大写金额(可选用现成库),小写金额去除逗号、货币符号。
  • 校验码验证:部分发票有校验码,可进行格式检查。

输出为 JSON

{
  "invoice_code": "031001900111",
  "invoice_number": "12345678",
  "date": "2024-03-15",
  "seller_name": "某某科技有限公司",
  "total_amount": 1580.00,
  "items": [
    {"name": "笔记本", "quantity": 2, "unit_price": 790.00}
  ]
}