如何基于Pytesseract从个人财务报表图片提取键值对?
用Pytesseract提取财务报表图片中的键值对方案
你现在的代码只能拿到零散的文本块和坐标,没法把键和对应的值关联起来。要解决这个问题,核心是利用坐标信息把同一行的文本归组,再根据位置或分隔符配对键值,同时可以通过图像预处理提升识别准确率。
具体调整步骤
1. 先做图像预处理
财务报表可能有背景干扰、表格线,先处理图像能让Tesseract识别更准:
- 灰度化:把彩色图转成黑白,减少颜色干扰
- 二值化:让文本和背景对比更强烈
- 去噪:消除小斑点等干扰
2. 利用坐标分组文本块
Tesseract返回的image_to_data结果里有top(行顶部坐标)和left(列左侧坐标):
- 把
top值相近的文本块归为同一行(报表里键值对基本同行) - 同一行内按
left排序,左边是键、右边是值(或者根据冒号拆分)
3. 配对键值对
要么根据文本里的冒号直接拆分,要么把同一行左侧的文本合并成键,右侧合并成值。
修改后的完整代码
import pytesseract import cv2 import numpy as np from PIL import Image import pandas as pd pytesseract.pytesseract.tesseract_cmd = r'path to tesseract' # 替换成你的Tesseract路径 # 图像预处理:提升识别准确率 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) # 去除小噪声 kernel = np.ones((1,1), np.uint8) cleaned_img = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel) # 转为PIL格式供Tesseract使用 return Image.fromarray(cleaned_img) # 提取并配对键值对 def get_key_value_pairs(image_path): preprocessed_img = preprocess_image(image_path) # 提取带坐标、行号的文本数据 extracted_data = pytesseract.image_to_data(preprocessed_img, lang='eng', output_type='data.frame') # 过滤空文本 extracted_data = extracted_data.replace(r'^\s*$', np.nan, regex=True).dropna(subset=['text']) # 按行分组:把top值相近的归为同一行(阈值可根据报表调整,比如5像素) extracted_data['row_group'] = pd.cut(extracted_data['top'], bins=1000, labels=False) key_value = {} # 遍历每一行的文本块 for _, row_group in extracted_data.groupby('row_group'): # 按左坐标排序,确保从左到右处理文本 sorted_text = row_group.sort_values('left') key_parts = [] value_parts = [] for _, text_row in sorted_text.iterrows(): text = text_row['text'].strip() # 优先按冒号拆分,这是最直接的方式 if ':' in text: k_part, v_part = text.split(':', 1) key_parts.append(k_part.strip()) value_parts.append(v_part.strip()) else: # 没有冒号的话,按行的中间位置划分左右,左为键、右为值 row_mid = sorted_text['left'].max() / 2 if text_row['left'] < row_mid: key_parts.append(text) else: value_parts.append(text) # 合并成完整的键和值 if key_parts and value_parts: final_key = ' '.join(key_parts).strip() final_value = ' '.join(value_parts).strip() key_value[final_key] = final_value return key_value # 测试运行 result = get_key_value_pairs('image.png') for k, v in result.items(): print(f"{k} : {v}")
额外优化建议
- 如果报表有明显的表格线,可以用OpenCV的霍夫线检测去除,减少干扰
- 调整Tesseract的页面分割模式(比如添加
config='--psm 6'),这个参数能告诉Tesseract文本的排版方式,6适合规整的块文本 - 对提取到的数值型值,可以做格式转换(比如
float(final_value)),方便后续计算
内容的提问来源于stack exchange,提问作者reven06
相关产品推荐
相关产品推荐

