Розробка AI для оцифрування паперових архівів
Уявіть: сотні тисяч сторінок документів, які роками пиляться в шафах. Ручне оцифрування такого обсягу — це роки роботи десятка операторів, помилки в датах і загублені сторінки. Ми впровадили AI-пайплайн для архіву з 500 000 сторінок — результат: 14 тижнів замість 3 років, а якість розпізнавання стабільно перевищила 95%. AI автоматизує ланцюжок: сканування → попередня обробка зображень → OCR → структурування → індексація. Типовий обсяг промислового архіву — сотні тисяч сторінок, які вручну обробляються роками. AI-pipeline скорочує час у 10–50 разів при порівнянній якості, а витрати знижуються в 5–8 разів. Це автоматизація архіву, яка окупається менш ніж за рік. Отримайте консультацію — оцінимо ваш архів і підберемо оптимальне рішення.
Наш сервіс автоматизації оцифрування архівів AI забезпечує високу якість OCR документів та розпізнавання тексту. Автоматизація архіву включає індексацію документів, пошук по архіву, обробку рукописів та історичних документів. Ми використовуємо нейромережі OCR (PaddleOCR) та попередню обробку зображень. Elasticsearch архів дозволяє швидко знаходити потрібну інформацію.
Які проблеми вирішуємо за допомогою AI
Основні проблеми
Низька якість вихідних матеріалів. Тіні, перекоси, нерівномірне освітлення — звичайна справа для архівних сканів. Без попередньої обробки OCR видає помилки в кожному другому слові. Ми застосовуємо CLAHE та морфологію для видалення тіней, вирівнювання через Hough Transform, та Sauvola бінаризацію — це стабільно підіймає accuracy до 95%.
Рукописний текст. Рукописи мають високу варіативність почерків. Використовуємо ансамбль з PaddleOCR та донавченої моделі на основі TrOCR для складних випадків. CER знижується до 2–6% при хорошій якості оригіналу.
Історичні документи. Вицвілі чорнила, плями, крихкий папір — потребують не лише цифрової обробки, але й акуратного фізичного сканування. Наш pipeline включає етап реставрації: видалення фону, відновлення контрасту, заповнення прогалин через inpainting.
Чому попередня обробка критична для якості OCR?
import cv2
import numpy as np
from PIL import Image, ImageEnhance
class DocumentPreprocessor:
"""
Предобработка влияет на качество OCR кардинально:
правильная бинаризация может поднять accuracy с 70% до 95%.
"""
def preprocess_scanned_page(self, image: np.ndarray,
dpi: int = 300) -> np.ndarray:
"""
Полный pipeline предобработки страницы.
DPI 300 минимум для OCR, 400+ для мелкого текста.
"""
# 1. Выравнивание наклона (deskew)
deskewed = self._deskew(image)
# 2. Удаление теней и неравномерного освещения
shadowless = self._remove_shadows(deskewed)
# 3. Адаптивная бинаризация (Sauvola)
binary = self._binarize_sauvola(shadowless)
# 4. Удаление шума и артефактов (пятна, пыль)
cleaned = self._remove_noise(binary)
# 5. Нормализация размера
if dpi != 300:
scale = 300 / dpi
h, w = cleaned.shape[:2]
cleaned = cv2.resize(cleaned, (int(w*scale), int(h*scale)),
interpolation=cv2.INTER_AREA)
return cleaned
def _deskew(self, image: np.ndarray) -> np.ndarray:
"""Коррекция угла наклона через Hough Transform"""
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) if len(image.shape) == 3 else image
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi/180, threshold=200)
if lines is None:
return image
angles = []
for line in lines[:20]: # берём только самые явные линии
rho, theta = line[0]
angle = np.degrees(theta) - 90
if abs(angle) < 45:
angles.append(angle)
if not angles:
return image
median_angle = np.median(angles)
if abs(median_angle) < 0.5: # незначительный наклон — пропускаем
return image
h, w = image.shape[:2]
M = cv2.getRotationMatrix2D((w/2, h/2), median_angle, 1.0)
return cv2.warpAffine(image, M, (w, h),
flags=cv2.INTER_CUBIC,
borderMode=cv2.BORDER_REPLICATE)
def _remove_shadows(self, image: np.ndarray) -> np.ndarray:
"""Устранение теней через CLAHE + морфология"""
if len(image.shape) == 3:
lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(lab)
else:
l = image
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
l_enhanced = clahe.apply(l)
# Вычитание градиента освещённости
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 50))
bg = cv2.morphologyEx(l_enhanced, cv2.MORPH_DILATE, kernel)
normalized = cv2.divide(l_enhanced, bg, scale=255)
if len(image.shape) == 3:
return cv2.cvtColor(cv2.merge([normalized, a, b]), cv2.COLOR_LAB2BGR)
return normalized
def _binarize_sauvola(self, image: np.ndarray,
window_size: int = 25,
k: float = 0.2) -> np.ndarray:
"""
Sauvola бинаризация: лучше Otsu для неравномерного фона.
window_size=25 — оптимум для большинства текстовых документов.
"""
from skimage.filters import threshold_sauvola
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) if len(image.shape) == 3 else image
thresh = threshold_sauvola(gray, window_size=window_size, k=k)
binary = (gray > thresh).astype(np.uint8) * 255
return binary
def _remove_noise(self, binary: np.ndarray,
min_blob_area: int = 20) -> np.ndarray:
"""Удаление мелких артефактов (пыль, царапины)"""
# Находим связные компоненты
num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(
binary, connectivity=8
)
# Удаляем компоненты меньше min_blob_area пикселей
clean = np.zeros_like(binary)
for i in range(1, num_labels):
if stats[i, cv2.CC_STAT_AREA] >= min_blob_area:
clean[labels == i] = 255
return clean
Як ми прискорюємо оцифрування: паралельна обробка
import asyncio
from pathlib import Path
from paddleocr import PaddleOCR
import json
import sqlite3
class ArchiveDigitizationPipeline:
def __init__(self, db_path: str, output_dir: str,
lang: str = 'ru'):
self.ocr = PaddleOCR(use_angle_cls=True, lang=lang,
use_gpu=True, show_log=False)
self.preprocessor = DocumentPreprocessor()
self.db = sqlite3.connect(db_path)
self.output_dir = Path(output_dir)
self._init_db()
def _init_db(self):
self.db.execute('''
CREATE TABLE IF NOT EXISTS documents (
id INTEGER PRIMARY KEY,
file_path TEXT UNIQUE,
status TEXT DEFAULT 'pending',
ocr_text TEXT,
metadata TEXT,
processed_at TIMESTAMP
)
''')
self.db.commit()
def process_batch(self, image_paths: list[str],
n_workers: int = 4) -> dict:
"""Параллельная обработка пакета документов"""
from concurrent.futures import ProcessPoolExecutor
from tqdm import tqdm
results = {'success': 0, 'failed': 0, 'errors': []}
with ProcessPoolExecutor(max_workers=n_workers) as executor:
futures = {
executor.submit(self._process_single, p): p
for p in image_paths
}
for future in tqdm(futures, total=len(futures),
desc='Digitizing archive'):
path = futures[future]
try:
result = future.result(timeout=120)
self._save_to_db(path, result)
results['success'] += 1
except Exception as e:
results['failed'] += 1
results['errors'].append(str(e))
return results
def _process_single(self, image_path: str) -> dict:
import cv2
image = cv2.imread(image_path)
preprocessed = self.preprocessor.preprocess_scanned_page(image)
ocr_result = self.ocr.ocr(preprocessed, cls=True)
if not ocr_result or not ocr_result[0]:
return {'text': '', 'lines': [], 'confidence': 0}
lines = []
confidences = []
for line in ocr_result[0]:
bbox, (text, conf) = line
lines.append({'text': text, 'confidence': conf, 'bbox': bbox})
confidences.append(conf)
full_text = '\n'.join(l['text'] for l in lines)
mean_confidence = float(np.mean(confidences)) if confidences else 0
return {
'text': full_text,
'lines': lines,
'confidence': mean_confidence,
'low_quality': mean_confidence < 0.7
}
Використовуємо PaddleOCR як основу OCR-движка. Він забезпечує високу якість розпізнавання російської мови та підтримує GPU-прискорення. Для складних випадків застосовуємо нейромережі OCR на базі TrOCR.
Повнотекстова індексація результатів
Повнотекстова індексація виконується за допомогою Elasticsearch з російським аналізатором.
import elasticsearch
class ArchiveSearchIndex:
def __init__(self, es_url: str, index_name: str = 'archive'):
self.es = elasticsearch.Elasticsearch([es_url])
self.index = index_name
self._create_index()
def _create_index(self):
mapping = {
'mappings': {
'properties': {
'file_path': {'type': 'keyword'},
'text': {
'type': 'text',
'analyzer': 'russian'
},
'confidence': {'type': 'float'},
'metadata': {'type': 'object'},
'processed_at': {'type': 'date'}
}
}
}
if not self.es.indices.exists(index=self.index):
self.es.indices.create(index=self.index, body=mapping)
def index_document(self, doc_id: str, text: str,
file_path: str, metadata: dict = None):
self.es.index(index=self.index, id=doc_id, body={
'text': text, 'file_path': file_path,
'metadata': metadata or {}
})
def search(self, query: str, size: int = 10) -> list:
result = self.es.search(index=self.index, body={
'query': {'match': {'text': query}},
'highlight': {'fields': {'text': {}}},
'size': size
})
return result['hits']['hits']
Для індексації використовуємо Elasticsearch з російським аналізатором. Це забезпечує швидкий пошук по архіву.
Як ми гарантуємо стабільну якість розпізнавання?
Після кожного етапу ми проводимо контрольні заміри на репрезентативній вибірці (мінімум 500 сторінок). Якщо CER перевищує 5% для друкованих документів, коригуємо гіперпараметри попередньої обробки або донавчаємо OCR-модель. Для рукописів поріг — 10%. При необхідності підключаємо ручну вивірку найскладніших фрагментів. Такий підхід забезпечує стабільну якість і низький CER навіть на складних вихідних матеріалах.
Що входить в результат?
Після завершення проекту ви отримуєте:
- Повний цифровий архів з розпізнаним текстом (PDF/A, TXT, JSON)
- Індекс Elasticsearch з повнотекстовим пошуком
- API для інтеграції з вашими системами (REST, SOAP)
- Документацію пайплайну та інструкції з експлуатації
- Навчання персоналу роботі з системою
- Гарантійну підтримку на 3 місяці
Покроковий процес впровадження AI-пайплайну
- Аудит архіву: оцінка обсягу, стану документів, підбір стеку (PaddleOCR, Elasticsearch, Python).
- Пілотний проект: оцифрування 1000 сторінок для калібрування пайплайну та фіксації метрик.
- Розробка та налаштування: підбір гіперпараметрів попередньої обробки, донавчання OCR-моделі при необхідності.
- Масштабування: запуск паралельної обробки на GPU-серверах з моніторингом в реальному часі.
- Інтеграція та пошук: налаштування Elasticsearch, розробка API для доступу до розпізнаних текстів.
- Тестування та приймання: контрольне розпізнавання всієї вибірки, виправлення систематичних помилок.
Очікувані результати та строки
| Параметр | Ручна обробка | AI-пайплайн |
|---|---|---|
| Час на 100 000 сторінок | 2–3 роки | 10–18 тижнів |
| Витрати (орієнтовно) | Вищі в 5–8 разів | Значно нижчі |
| Якість OCR | Залежить від оператора | Стабільна, CER <5% |
| Обсяг архіву | Строк |
|---|---|
| 10,000–50,000 сторінок (стандартні документи) | 4–8 тижнів |
| 100,000+ сторінок з pipeline та індексацією | 10–18 тижнів |
| Історичний архів з рукописами та реставрацією | 20–36 тижнів |
AI-пайплайн обробляє документи в 10–50 разів швидше за людину при тій же якості — це пряме порівняння, підтверджене нашими проектами. Наприклад, для архіву обсягом 100 000 сторінок економія становить приблизно €30,000–€60,000.
Чек-лист підготовки архіву до оцифрування
- Переконайтеся, що всі документи розсортовані та очищені від скріпок/файлів.
- Відскануйте документи в кольорі з роздільною здатністю 300 dpi (мінімум).
- Перевірте, що скани не мають сильних перекосів (ідеально — рівні).
- Розбийте архів на логічні одиниці (папки, справи).
- Надайте метадані (дати, номери справ) для зв’язки.







