Реализация распознавания таблиц из изображений/PDF
Извлечение таблиц — задача, где обычный OCR возвращает текст без структуры: строки и столбцы теряются. Задача Table Recognition состоит из двух подзадач: Table Detection (найти таблицу в документе) и Table Structure Recognition (восстановить сетку строк/столбцов). Результат — структурированные данные, пригодные для загрузки в DataFrame или базу данных.
Table Transformer (Microsoft TATR)
State-of-the-art: Table Transformer от Microsoft, основан на DETR, обучен на PubTables-1M (947k таблиц из научных публикаций):
from transformers import TableTransformerForObjectDetection, DetrImageProcessor
from PIL import Image
import torch
class TableExtractor:
def __init__(self):
# Детектор таблиц
self.det_processor = DetrImageProcessor.from_pretrained(
'microsoft/table-transformer-detection'
)
self.det_model = TableTransformerForObjectDetection.from_pretrained(
'microsoft/table-transformer-detection'
)
# Структурный распознаватель
self.str_processor = DetrImageProcessor.from_pretrained(
'microsoft/table-transformer-structure-recognition'
)
self.str_model = TableTransformerForObjectDetection.from_pretrained(
'microsoft/table-transformer-structure-recognition'
)
def extract_tables(self, image_path: str) -> list[dict]:
image = Image.open(image_path).convert('RGB')
# 1. Детектируем таблицы
table_boxes = self._detect_tables(image)
tables = []
for box in table_boxes:
# 2. Кропаем каждую таблицу
table_crop = image.crop(box)
# 3. Распознаём структуру (строки/столбцы)
structure = self._recognize_structure(table_crop)
# 4. Извлекаем текст из ячеек через OCR
cells = self._extract_cell_texts(table_crop, structure)
tables.append({
'bbox': box,
'structure': structure,
'cells': cells,
'dataframe': self._cells_to_dataframe(cells)
})
return tables
def _detect_tables(self, image: Image.Image) -> list[tuple]:
inputs = self.det_processor(images=image, return_tensors='pt')
with torch.no_grad():
outputs = self.det_model(**inputs)
target_sizes = torch.tensor([image.size[::-1]])
results = self.det_processor.post_process_object_detection(
outputs, threshold=0.7, target_sizes=target_sizes
)[0]
boxes = []
for label, box in zip(results['labels'], results['boxes']):
if label == 0: # table class
x1, y1, x2, y2 = box.tolist()
boxes.append((int(x1), int(y1), int(x2), int(y2)))
return boxes
Альтернатива: camelot для PDF
Для digitally created PDF (не сканы) — camelot без ML:
import camelot
def extract_tables_from_pdf(pdf_path: str,
pages: str = 'all') -> list:
# Lattice: для таблиц с явными линиями
tables_lattice = camelot.read_pdf(
pdf_path, pages=pages, flavor='lattice'
)
# Stream: для таблиц без линий (выровненный текст)
tables_stream = camelot.read_pdf(
pdf_path, pages=pages, flavor='stream',
edge_tol=50
)
results = []
for table in tables_lattice:
if table.accuracy > 80:
results.append({
'page': table.page,
'accuracy': table.accuracy,
'dataframe': table.df,
'csv': table.df.to_csv(index=False)
})
return results
pdfplumber для смешанных документов
import pdfplumber
import pandas as pd
def extract_tables_pdfplumber(pdf_path: str) -> list[pd.DataFrame]:
tables = []
with pdfplumber.open(pdf_path) as pdf:
for page in pdf.pages:
page_tables = page.extract_tables(
table_settings={
'vertical_strategy': 'lines',
'horizontal_strategy': 'lines',
'snap_tolerance': 3
}
)
for raw_table in page_tables:
# Первая строка как заголовок
df = pd.DataFrame(raw_table[1:], columns=raw_table[0])
tables.append(df)
return tables
Постобработка: очистка данных таблицы
После извлечения часто нужна очистка:
def clean_table(df: pd.DataFrame) -> pd.DataFrame:
# Удаление пустых строк и столбцов
df = df.dropna(how='all').dropna(axis=1, how='all')
# Объединение многострочных заголовков
df.columns = [' '.join(str(c).split()) for c in df.columns]
# Числовые столбцы
for col in df.columns:
try:
df[col] = pd.to_numeric(
df[col].str.replace(',', '.').str.replace(' ', ''),
errors='ignore'
)
except AttributeError:
pass
return df
| Подход | Применение | Качество |
|---|---|---|
| Table Transformer | Сканы, изображения | Хорошее |
| camelot (lattice) | PDF с линиями | Отличное |
| camelot (stream) | PDF без линий | Среднее |
| pdfplumber | Smешанные PDF | Хорошее |
| AWS Textract | Облако, масштаб | Хорошее |
| Задача | Срок |
|---|---|
| Извлечение из PDF (camelot/pdfplumber) | 1 неделя |
| Сканы + Table Transformer | 2–3 недели |
| Сложные таблицы, post-processing | 3–5 недель |







