基于paddle模型 文本识别

文字识别模型onnx的输入输出如下:

  1. 模型输出维度[batch_size, 80, 6625]

    • 80:时间步(max_chars)
    • 6625:词表大小(vocab_size)
  2. 词表结构 (通过 loadCharDict() 构建):

    cpp 复制代码
    m_char_dict.push_back("#BLANK#");  // 索引 0 → CTC blank
    while (getline(file, line)) {
        m_char_dict.push_back(line);   // 索引 1 ~ 6623 → 6623 个有效字符
    }
    m_char_dict.push_back(" ");        // 索引 6624 → 空格
    • 总大小:1 + 6623 + 1 = 6625
    • 索引 0 是 blank,索引 6624 是空格
  3. ArgMax 范围

    • 代码中:

      cpp 复制代码
      int argmax_idx = 0;
      float max_value = p_step[0];
      for (int j = 1; j < vocab_size; ++j) { ... }
    • 这实际上遍历了全部 6625 个维度 (因为初始值是 p_step[0],循环从 j=16624

    • ✅ 包含索引 0(blank)和索引 6624(空格)

  4. 解码时跳过 blank

    • 通过 if (argmax_idx > 0 && ...) 实现
    • ✅ 空格(索引 6624)会被保留

🧠 整体解码思路:CTC Greedy Decoding

输入

  • 模型原始输出:float output[batch_size][80][6625]
    • 每个 [80][6625] 块对应一张图像
    • 每个时间步 t ∈ [0,79] 输出一个 6625 维 logits 向量

输出

  • std::vector<TextLine>,每个 TextLine 包含:
    • .text:识别出的字符串(如 "粤B88888"
    • .score:平均置信度(0~1)

🔁 后处理流程详解(逐步骤)

步骤 1️⃣:遍历每个样本(batch)

cpp 复制代码
for (int i = 0; i < batch_size; ++i) {
    float* parray = p_output + i * 80 * 6625;
  • 定位到当前图像的输出数据块

步骤 2️⃣:对每个时间步做 ArgMax

cpp 复制代码
for (int t = 0; t < 80; ++t) {
    float* p_step = parray + t * 6625;

    // 找出概率最大的类别索引(0~6624)
    int argmax_idx = 0;
    float max_value = p_step[0];
    for (int j = 1; j < 6625; ++j) {
        if (p_step[j] > max_value) {
            max_value = p_step[j];
            argmax_idx = j;
        }
    }
  • 结果 :得到长度为 80 的整数序列,如 [0, 0, 27, 27, 27, 0, 64, 64, ..., 6624]

步骤 3️⃣:CTC 解码(去 blank + 去重)

cpp 复制代码
if (argmax_idx > 0 && !(t > 0 && argmax_idx == last_index)) {
    // 加入字符
    result.text += m_char_dict[argmax_idx];
}
last_index = argmax_idx;
规则解释:
条件 作用 示例
argmax_idx > 0 跳过 blank(索引 0) 0 → 忽略
!(t > 0 && argmax_idx == last_index) 折叠连续重复字符 [..., 27, 27, ...] → 只取第一个 27

💡 注意

  • 空格(索引 6624)满足 argmax_idx > 0会被保留
  • 如果出现 [6624, 6624] → 第二个空格被去重 → 结果只有一个空格

步骤 4️⃣:安全与评分

  • 索引越界检查:防止模型输出非法索引
  • NaN/Inf 过滤:避免数值异常
  • 平均置信度score = sum(max_value) / count

📊 完整示例演示

假设某图像的 ArgMax 序列为(只展示前 10 步):

t argmax_idx 字符 是否加入 说明
0 0 #BLANK# blank 跳过
1 27 '粤' 首次出现
2 27 '粤' 与上一重复
3 0 #BLANK# blank
4 64 'B' 新字符
5 64 'B' 重复
6 32 '8' 新字符
7 32 '8' 重复
8 32 '8' 重复
9 6624 ' ' 空格(有效字符)

最终文本"粤B8 "(注意末尾有空格)


⚠️ 关键注意事项(再次强调)

  1. ArgMax 覆盖全部 6625 维

    • 虽然循环从 j=1 开始,但 max_value 初始化为 p_step[0]索引 0 被包含
    • 空格(6624)也被包含
  2. 只有 blank(索引 0)被跳过

    • 所有其他索引(包括 6624)都是有效字符
  3. t > 0 是必要的边界保护

    • 确保第 0 个时间步不会因 last_index 初始值被误判为重复
  4. 该逻辑适用于 CTC 模型

    • PaddleOCR 默认使用 CTC Loss,因此此解码正确

✅ 总结:输入 → 输出映射

阶段 输入 处理 输出
模型推理 图像 [3, H, W] CNN + RNN/Transformer Logits [80, 6625]
ArgMax Logits 找每列最大值 索引序列 [80](0~6624)
CTC 解码 索引序列 去 blank + 去重 字符串(如 "粤B88888"

这套流程高效、鲁棒,是工业 OCR 系统的标准实践。

相关推荐
彭祥.2 天前
基于PaddleSeg与YOLO的自动标注工具
yolo·paddle
Qt学视觉5 天前
AI2-Paddle环境搭建
c++·人工智能·python·opencv·paddle
gzroy1 个月前
华为昇腾服务器部署Paddle OCR VL模型及推理服务
ocr·paddle
天天代码码天天2 个月前
lw.PPOCRSharp_GPU_Test paddle_inference v3.3
人工智能·深度学习·paddle
weixin_462446232 个月前
使用 PaddleOCR + 多进程 + GPU 加速实现 PDF 可搜索化(支持中英文、竖排/旋转文字)
pdf·paddle·识别
FL16238631292 个月前
Windows上GPU版本的Paddle Inference3.2.1安装和使用教程
windows·paddle
YQ_012 个月前
Ubuntu 18.04 离线安装 CUDA 11.2 + cuDNN 8.2 (修复 Paddle 缺少 .so 报错)
linux·ubuntu·paddle
AI街潜水的八角2 个月前
基于paddle框架的MobileNetV2深度学习神经网络番茄/西红柿叶子病虫害识别系统源码
深度学习·神经网络·paddle