如何提升图像嵌入型PDF文件的表格数据提取准确率?
你当前用pdf2image+pytesseract实现了基础的图像PDF文本提取,但针对表格场景,需要从图像预处理、OCR参数调优、表格结构解析这几个维度优化,具体方案如下:
你的现有代码
from pdf2image import convert_from_path import pytesseract import csv from pytesseract import Output # 将PDF转换为图片 images = convert_from_path('input.pdf') # 创建CSV文件 csv_file_path = 'output.csv' with open(csv_file_path, 'w', newline='', encoding='utf-8') as csv_file: csv_writer = csv.writer(csv_file) # 遍历每张图片 for i, image in enumerate(images): # 保存图片 image_path = f'page_{i}.png' image.save(image_path, 'PNG') # 使用pytesseract从图片中提取文本 text = pytesseract.image_to_string(image_path, output_type=Output.STRING) # 打印提取的文本 print(text) # 将文本写入CSV文件 csv_writer.writerow([text]) print(f'CSV文件已生成,路径:{csv_file_path}')
一、图像预处理:消除干扰,提升OCR识别基础
图像质量是OCR准确率的核心,先对PDF转换后的图片做预处理:
灰度转换+二值化:去除颜色干扰,强化文本与背景的对比度
import cv2 import numpy as np def preprocess_image(image_path): # 读取图片并转灰度 img = cv2.imread(image_path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 自适应二值化(适合光照不均的情况) thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) # 保存预处理后的图片 processed_path = f'processed_{image_path}' cv2.imwrite(processed_path, thresh) return processed_path在你的代码中,替换
image_path为预处理后的路径再进行OCR。降噪处理:针对有斑点、划痕的图片,用高斯模糊或中值滤波去除噪点
# 在预处理函数中添加: blur = cv2.GaussianBlur(gray, (3,3), 0) # 或者中值滤波(适合椒盐噪点) blur = cv2.medianBlur(gray, 3)倾斜校正:如果表格存在倾斜,先检测并校正
def correct_skew(image): coords = np.column_stack(np.where(image > 0)) angle = cv2.minAreaRect(coords)[-1] if angle < -45: angle = -(90 + angle) else: angle = -angle (h, w) = image.shape[:2] center = (w // 2, h // 2) M = cv2.getRotationMatrix2D(center, angle, 1.0) rotated = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE) return rotated把这个步骤加入预处理流程,确保表格水平对齐。
二、Tesseract参数调优:针对表格场景优化识别逻辑
默认的Tesseract参数更适合普通文本,针对表格需要调整:
指定语言:如果是中文表格,必须指定语言包,避免乱码
text = pytesseract.image_to_string(processed_path, lang='chi_sim+eng', output_type=Output.STRING)注意要提前安装对应语言的Tesseract语言包。
调整PSM(页面分割模式):表格是结构化文本,推荐使用PSM 6(假设页面是一个统一的文本块)或PSM 11(稀疏文本,适合有空白单元格的表格)
text = pytesseract.image_to_string(processed_path, lang='chi_sim+eng', config='--psm 6 --oem 3', output_type=Output.STRING)--oem 3表示使用默认的OCR引擎模式。获取结构化坐标数据:不直接提取纯文本,而是获取每个字符的位置信息,方便后续按表格行列拆分
# 输出包含坐标的字典 data = pytesseract.image_to_data(processed_path, lang='chi_sim+eng', output_type=Output.DICT) # 可以遍历data中的'left', 'top', 'width', 'height', 'text'字段,按行分组
三、表格结构解析:按行列拆分数据,生成规范CSV
纯文本提取无法区分表格的行列,需要基于坐标或线条检测来拆分:
基于坐标分组行:利用Tesseract返回的
top坐标,将垂直距离相近的字符归为同一行,再按left坐标排序得到列数据def parse_table_from_data(data): rows = [] current_row = [] prev_top = -100 # 初始阈值 # 遍历每个识别结果 for i in range(len(data['text'])): text = data['text'][i].strip() if not text: continue top = data['top'][i] # 当垂直距离超过阈值时,新建一行 if abs(top - prev_top) > 10: if current_row: rows.append(current_row) current_row = [text] prev_top = top else: current_row.append(text) if current_row: rows.append(current_row) return rows然后把
rows直接写入CSV,就能得到行列分明的表格数据。OpenCV检测表格线条:如果表格有明显边框,先检测水平线和垂直线,分割出每个单元格,再对单个单元格做OCR,准确率更高
def detect_table_cells(image_path): img = cv2.imread(image_path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) # 检测水平线 horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40,1)) detect_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2) # 检测垂直线 vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,40)) detect_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2) # 合并线条 combined = cv2.addWeighted(detect_horizontal, 0.5, detect_vertical, 0.5, 0.0) # 找到轮廓 contours, _ = cv2.findContours(combined, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 按坐标排序轮廓(先按行,再按列) contours = sorted(contours, key=lambda c: (cv2.boundingRect(c)[1], cv2.boundingRect(c)[0])) cells = [] for cnt in contours: x, y, w, h = cv2.boundingRect(cnt) if w > 20 and h > 20: # 过滤小轮廓 cell_img = img[y:y+h, x:x+w] # 对单元格做OCR cell_text = pytesseract.image_to_string(cell_img, lang='chi_sim+eng').strip() cells.append(cell_text) # 按表格行列数拆分cells(需要提前知道列数,或者动态计算) return cells
四、进阶工具组合:针对复杂表格的替代方案
如果上述优化仍不够,可尝试专门的表格OCR工具:
- PaddleOCR表格识别:百度开源的OCR工具,内置表格结构解析模型,能直接输出行列结构化数据
- EasyOCR:轻量开源OCR,支持多语言,配合坐标处理也能实现表格提取
内容的提问来源于stack exchange,提问作者Xian Klein

