You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Tesseract识别连字符/减号以提取毕业证表格成绩数据

基于Tesseract识别毕业证表格成绩的优化方案

需求背景

使用Tesseract识别毕业证上的类表格结构成绩信息,采用将表格按列拆分后分别识别、再合并为tibble格式的方案,适配不同列的字符/整数类型要求。

现存问题

表格中空单元格使用连字符-填充,即使已经在字符白名单中添加了连字符、下划线和小数点,Tesseract仍无法识别该符号,导致不同列识别结果元素数量不一致、列长不匹配,无法合并为统一的tibble。

解决方案

1. 优化图像预处理强化连字符特征

连字符识别率低通常是因为笔画过细、对比度不足,调整预处理逻辑:

  • 新增反色后膨胀操作,强化细笔画的连字符特征,处理完成后再恢复原始配色
  • 取消透明化处理逻辑,避免连字符边缘被误判为背景抹除,改用二值化处理提升字符与背景的对比度
  • 提高识别dpi到720,更高分辨率能保留更多连字符的细节特征

2. 修正Tesseract配置

原有白名单配置和词库规则会过滤连字符,调整引擎参数:

  • 数字专用白名单将连字符放在最前面,避免被后续特殊规则覆盖
  • 关闭Tesseract自带的词库匹配功能,避免连字符被误判为无效字符过滤

3. 新增列长对齐兜底逻辑

即使优化识别率后仍可能存在极个别识别误差,新增列长对齐逻辑:

  • 以课程名列(长度最稳定)的行数为基准值
  • 其余列如果行数少于基准值,自动补-;如果行数多于基准值,过滤空识别结果后取前N条匹配基准长度

修正后代码

# 仅需下载一次德语训练集
tesseract_download("deu")
# 加载德语识别引擎
deutsch <- tesseract("deu")

library(pdftools)
library(magick)
library(tidyverse)

# 渲染PDF第二页,提升dpi到720保留更多细节
bitmap <- pdf_render_page('./example.pdf', page = 2, dpi = 720)
abiturzeugnis <- image_read(bitmap)

# 优化预处理逻辑,强化连字符特征
no_grid <- abiturzeugnis %>%
  image_deskew() %>% 
  image_quantize(colorspace = "gray") %>% 
  # 二值化提升对比度
  image_threshold(type = "black", threshold = "50%") %>%
  image_threshold(type = "white", threshold = "50%") %>%
  # 反色后膨胀强化细笔画,再反色恢复
  image_negate() %>%
  image_morphology(method = "dilate", kernel = "rectangle:2x1") %>%
  image_negate()

# 优化OCR识别函数
img_ocr_fun <- function(trim_width, trim_start, char_num = TRUE) {
  # 调整白名单顺序,关闭词库匹配避免连字符被过滤
  num_only <- tesseract::tesseract(    
    options = list(
      tessedit_char_whitelist = "-._0123456789 ",
      load_system_dawg = FALSE,
      load_freq_dawg = FALSE
    )
  )
  combo <- tesseract::tesseract(
    options = list(
      tessedit_char_whitelist = paste0(
        c("-", letters, LETTERS, " ", "._0123456789()", "ä", "ö", "ü", "Ä", "Ö", "Ü"), collapse = ""),
      load_system_dawg = FALSE,
      load_freq_dawg = FALSE
    )
  )
  
  input_char <- if (isTRUE(char_num)) {
    num_only
  } else {
    combo
  }
  # 调整裁剪参数匹配新的dpi
  ocr_res <- no_grid %>%
    image_crop(geometry_area(trim_width, 3816, trim_start, 1680)) %>%
    ocr(engine = input_char) %>%
    str_split(pattern = "\n") %>%
    unlist() %>%
    str_squish() %>%
    enframe(name = NULL, value = "value") %>%
    filter(!is.na(value))
  return(ocr_res)
}

# 按列识别
all_ocr <- list(
  trim_width = c(750, 115, 105, 100, 100, 600),
  trim_start = c(270, 1210, 1460, 1700, 1950, 2125),
  char_num = c(FALSE, TRUE, TRUE, TRUE, TRUE, FALSE)
) %>%  
  purrr::pmap(img_ocr_fun) 

# 列长对齐逻辑,以课程名列长度为基准
base_len <- nrow(all_ocr[[1]])
all_ocr_aligned <- map(all_ocr, function(col_df) {
  col_vec <- col_df$value
  if (length(col_vec) < base_len) {
    # 长度不足补-
    col_vec <- c(col_vec, rep("-", base_len - length(col_vec)))
  } else if (length(col_vec) > base_len) {
    # 长度过长过滤空值后匹配基准长度
    col_vec <- col_vec[col_vec != ""][1:base_len]
    col_vec[is.na(col_vec)] <- "-"
  }
  return(tibble(value = col_vec))
})

# 合并为结果表
data_df <- all_ocr_aligned %>% 
  bind_cols() %>% 
  set_names(nm = c("Fach", "11 I", "11 II", "12 I", "12 II", "Note")) 

data_df

内容的提问来源于stack exchange,提问作者RKF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 04:54:01