从含模糊图片的PDF提取表格存CSV:OCR提取异常求助
模糊PDF表格提取问题及优化方案
问题背景
手中有多页均为模糊图片的PDF,需要提取每页的表格并保存为独立CSV。已将PDF转成JPEG图片,使用TesseractOCR结合img2table提取,但存在两个核心问题:
- 原图中
motor gasoline是跨两列的表头,对应“thousands of barrels per day”和“% change”两个子项,但提取后仅被识别为第一列表头,未覆盖右侧列 - 原图中的“% change”字段完全遗漏,导致对应数据无匹配表头
当前使用的代码如下:
def extract_data_from_table_ocr(): from img2table.ocr import TesseractOCR from img2table.document import Image # 初始化OCR ocr = TesseractOCR(n_threads=1, lang="eng") # 加载图片文档 doc = Image('out3.jpg', dpi=200) # 提取表格 extracted_tables_all = doc.extract_tables(ocr=ocr, implicit_rows=True, borderless_tables=True, min_confidence=50) print("表格数量 : " , len(extracted_tables_all)) extracted_tables = extracted_tables_all[0] frames = [] for table in extracted_tables_all: try: frames.append(table.df) except: frames.append(table) result = pd.concat(frames) result.to_csv('tableConverted2.csv', index=False, header = False)
优化方案
1. 图片预处理提升OCR识别精度
模糊是识别遗漏的核心原因,先对图片做预处理强化文字辨识度:
- 灰度化+自适应二值化:消除色彩干扰,强化文字与背景边界
- 去噪处理:用中值滤波清除图片噪点
- 对比度增强:优化明暗对比,让模糊文字更清晰
用OpenCV实现预处理的代码:
import cv2 def preprocess_image(img_path): img = cv2.imread(img_path) # 灰度化 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 自适应二值化,适配明暗不均的图片 thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) # 中值滤波去噪 denoised = cv2.medianBlur(thresh, 3) # 保存预处理后的图片 processed_path = f"processed_{img_path}" cv2.imwrite(processed_path, denoised) return processed_path
2. 调整提取参数+修复表头结构
针对跨列表头和字段遗漏问题,优化提取逻辑:
- 提高
min_confidence阈值,过滤低置信度的无效识别结果 - 启用
split_text,拆分紧密排列的文字避免字段合并 - 手动修复跨列表头,补充遗漏的子表头信息
修改后的提取代码:
import pandas as pd from img2table.ocr import TesseractOCR from img2table.document import Image def extract_data_from_table_ocr(): # 预处理图片 processed_img = preprocess_image('out3.jpg') # 初始化OCR,设置psm参数优化文本分割(psm 6:假设图片为单一文本块) ocr = TesseractOCR(n_threads=1, lang="eng", psm=6) # 加载预处理后的图片 doc = Image(processed_img, dpi=200) # 提取表格,调整核心参数 extracted_tables_all = doc.extract_tables(ocr=ocr, implicit_rows=True, borderless_tables=True, min_confidence=70, # 提高置信度,减少错误识别 split_text=True) # 拆分紧密文字,避免字段遗漏 print("表格数量 : " , len(extracted_tables_all)) frames = [] for table in extracted_tables_all: try: df = table.df # 修复跨列表头和遗漏的% change字段 if 'motor gasoline' in str(df.iloc[0,0]): # 设置跨列表头 df.columns = ['motor gasoline', 'motor gasoline', 'distillate fuel oil', 'distillate fuel oil'] # 移除原表头行 df = df.drop(0).reset_index(drop=True) # 补充子表头,还原表格结构 df.columns = pd.MultiIndex.from_tuples([ (df.columns[0], 'thousands of barrels per day'), (df.columns[1], '% change'), (df.columns[2], 'thousands of barrels per day'), (df.columns[3], '% change') ]) frames.append(df) except Exception as e: print(f"处理表格出错: {e}") if frames: result = pd.concat(frames) result.to_csv('tableConverted2.csv', index=False) # 调用函数 extract_data_from_table_ocr()
3. 批量处理多页PDF
如果需要处理多页PDF,可结合PyMuPDF批量转高清图片,再循环提取每页表格:
import fitz # PyMuPDF import os def pdf_to_images(pdf_path, output_folder='pdf_images'): os.makedirs(output_folder, exist_ok=True) doc = fitz.open(pdf_path) for page_num in range(len(doc)): page = doc.load_page(page_num) # 生成300DPI高清图片,提升识别精度 pix = page.get_pixmap(dpi=300) img_path = os.path.join(output_folder, f'page_{page_num+1}.jpg') pix.save(img_path) # 处理当前页图片并保存为独立CSV processed_img = preprocess_image(img_path) extract_single_table(processed_img, f'table_page_{page_num+1}.csv') def extract_single_table(img_path, output_csv): ocr = TesseractOCR(n_threads=1, lang="eng", psm=6) doc = Image(img_path, dpi=300) extracted_tables_all = doc.extract_tables(ocr=ocr, implicit_rows=True, borderless_tables=True, min_confidence=70, split_text=True) frames = [] for table in extracted_tables_all: try: df = table.df if 'motor gasoline' in str(df.iloc[0,0]): df.columns = ['motor gasoline', 'motor gasoline', 'distillate fuel oil', 'distillate fuel oil'] df = df.drop(0).reset_index(drop=True) df.columns = pd.MultiIndex.from_tuples([ (df.columns[0], 'thousands of barrels per day'), (df.columns[1], '% change'), (df.columns[2], 'thousands of barrels per day'), (df.columns[3], '% change') ]) frames.append(df) except Exception as e: print(f"处理图片{img_path}出错: {e}") if frames: result = pd.concat(frames) result.to_csv(output_csv, index=False) # 调用批量处理 pdf_to_images('your_input.pdf')
内容的提问来源于stack exchange,提问作者FaisalShakeel
相关产品推荐
相关产品推荐

