OCR 圈子里,有一个共识:OCR 的准确率,70% 取决于图像预处理,30% 才取决于识别模型。

Google 和百度的 OCR 确实强,但前提是你喂给它们一张平整、清晰、无阴影的图片。一旦遇到用户躺在床上侧着拍的、带有手指阴影的、或者折痕严重的A4纸,通用 OCR 的识别率会断崖式下跌。

合合信息(TextIn)之所以能在这个细分领域封神,靠的不是识字快,而是它那套变态的 “文档还原引擎”

1. 核心壁垒:把“弯”的掰“直” (Dewarping)

手机摄影最大的敌人是 透视形变纸张弯曲

普通的 OpenCV 透视变换(Perspective Transform)只能处理刚性平面(也就是整张纸是平的,只是斜了),找四个角点做个矩阵变换就完事了。

但 TextIn 解决的是 非刚性形变。纸是弯的,上面有曲面。 TextIn 的算法模型预测的不是简单的四个角点,而是一个密集的 3D 网格 (Mesh)。它会预测出图片中纸张的几何卷曲程度,然后通过像素重映射(Remapping),像熨斗一样把图片“熨平”。

这是为什么扫描全能王拍出来的图看起来像扫描仪扫的原因。

2. 搞定“死亡光线”:基于 GAN 的去阴影

用户拍照时,手机挡住了顶灯,纸面上就会留下一大块手机和手的阴影。这对二值化算法是毁灭性的打击。

TextIn 在这里引入了 GAN (生成对抗网络)

  • 生成器 (Generator):负责“脑补”阴影下的像素原本是什么颜色(通常是白纸黑字)。
  • 判别器 (Discriminator):负责判断这张图是“自然拍摄的无阴影图”还是“算法P过的图”。

两者博弈的结果是,它能把阴影层的像素值减去,同时保留字迹的像素值。

3. 表格还原:从“画框”到“图神经网络”

最让开发者头疼的是:手机拍的表格,怎么还原成 Excel?

传统的表格识别(如 PaddleOCR 的早期版本)通常是检测横竖线。如果表格没有线(无线表),或者光照太强导致线断了,模型就瞎了。

TextIn 的思路是基于 GCN (图卷积神经网络)

  1. 节点 (Nodes):先把所有的文本块(Cell)检测出来,作为图的节点。
  2. 边 (Edges):然后预测节点之间的关系(谁是谁的左邻居,谁是谁的上一行)。
  3. 结构化:通过这种拓扑关系,重构出表格结构。

这种方法最大的优势是:它不在乎有没有表格线,也不在乎单元格有没有合并,只要文字排版上有对齐关系,它就能还原。

4. 代码实战:调用 TextIn API 实现“烂图转 Excel”

合合信息的服务主要通过 TextIn API 交付。要把一张烂图变成 Excel,通常需要两个步骤的组合拳:智能切边增强 + 通用表格识别

以下 Python 代码展示了如何调用 TextIn API 处理一张手机实拍的弯曲表格:

Python

import requests
import json
import base64

# 请去 textin.com 注册申请 appId 和 secretCode
APP_ID = 'your_app_id'
SECRET_CODE = 'your_secret_code'

def get_file_content(file_path):
    with open(file_path, 'rb') as fp:
        return fp.read()

def recognize_table_from_scan(image_path):
    # 1. URL 设置
    # TextIn 提供了专门的 "表格识别" 接口
    url = 'https://api.textin.com/ai/service/v2/recognize/table'
    
    # 2. 读取图片
    image_data = get_file_content(image_path)
    
    # 3. 构造请求头和鉴权
    headers = {
        'x-ti-app-id': APP_ID,
        'x-ti-secret-code': SECRET_CODE
    }
    
    # 4. 关键参数配置
    # excel: 1 表示直接返回 excel 文件流
    # json: 1 表示返回结构化的 json 数据 (单元格坐标、行列信息)
    # use_pdf: 如果输入是pdf设为1
    params = {
        'excel': 1, 
        'json': 1 
    }
    
    print(f"正在上传并处理图片: {image_path} ...")
    
    # 5. 发送请求
    # 注意:TextIn 的处理耗时比普通 OCR 稍长,因为它在后台做了复杂的图像矫正
    response = requests.post(url, data=image_data, headers=headers, params=params)
    
    if response.status_code == 200:
        result = json.loads(response.text)
        if result.get('code') == 200:
            # 6. 处理 Excel 结果
            # API 会返回一个 base64 编码的 excel 文件
            excel_base64 = result['result']['excel']
            save_path = image_path + ".xlsx"
            
            with open(save_path, 'wb') as f:
                f.write(base64.b64decode(excel_base64))
                
            print(f"成功!Excel 已保存至: {save_path}")
            
            # 7. (可选) 解析 JSON 结构看细节
            # print(result['result']['tables']) 
        else:
            print(f"识别失败: {result.get('message')}")
    else:
        print(f"HTTP 请求失败: {response.status_code}")

if __name__ == "__main__":
    # 找一张那种侧着拍、有阴影的表格图试试
    img_file = 'mobile_photo_table.jpg' 
    recognize_table_from_scan(img_file)

5. 什么时候选 TextIn?

作为技术选型者,你要非常清楚它的定位:

  • 不要用它做:简单的截屏文字识别、高并发的爬虫验证码识别。因为 TextIn 的单次调用成本(价格和耗时)通常高于百度/腾讯的通用 OCR。
  • 一定要用它做
    1. 报销/财务类 App:用户上传的发票、小票永远是皱的。
    2. 试卷/作业类 App:学生拍的试卷永远是弯的。
    3. 档案数字化:如果你的源数据是陈旧的纸质档案,且需要高保真还原版面。

TextIn 本质上卖的不是 OCR,而是 “把手机变成扫描仪” 的图像处理能力。