Пайплайн OCR для фотографий документов
Фотография документа — не скан. Типичные проблемы: перспективные искажения (текст становится трапецией), тени от пальцев и переплёта, неравномерное освещение, смазанность при движении, отражения на глянцевых поверхностях. Качественная система распознавания должна исправлять все эти искажения до передачи в OCR-движок. Без предобработки даже лучшие модели (PaddleOCR, GPT-4o) показывают CER 20–30% на таких фото. Для паспортов и удостоверений требуется CER <5% — это достижимо только с комплексным пайплайном.
Мы разработали решение, которое автоматически детектирует документ, выравнивает перспективу, убирает тени и блики, и только затем запускает OCR. Такой подход даёт стабильно низкую ошибку даже на неидеальных снимках. Наш пайплайн обрабатывает кадр за ~200 мс на GPU и уже внедрён в проектах для банков и государственных организаций — более 5 лет опыта, более 20 успешных интеграций.
Как мы выравниваем документ на фотографии?
Первая задача — найти документ в кадре и исправить перспективу. Типичная ситуация: пользователь фотографирует паспорт под углом, и текст становится нечитаемым для обычного OCR. Мы используем детекцию контуров на изображении после предобработки: перевод в серый, размытие, выделение границ оператором Canny, затем поиск четырёхугольника, занимающего >20% кадра. Если такой контур найден — применяем перспективную трансформацию (homography). Это даёт фронтальный вид документа.
import cv2 import numpy as np class DocumentPhotoOCR: def __init__(self): self.ocr = PaddleOCR(use_angle_cls=True, lang='ru', use_gpu=True) def process(self, image_path: str) -> dict: image = cv2.imread(image_path) # 1. Детекция документа в кадре doc_corners = self.detect_document(image) # 2. Перспективная коррекция if doc_corners is not None: image = self.four_point_transform(image, doc_corners) # 3. Улучшение качества изображения image = self.enhance_document(image) # 4. OCR result = self.ocr.ocr(image, cls=True) return { 'text': self._extract_text(result), 'words': self._extract_words_with_positions(result), 'corrected': doc_corners is not None } def detect_document(self, image: np.ndarray) -> np.ndarray | None: gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray, (5, 5), 0) edges = cv2.Canny(blur, 75, 200) dilated = cv2.dilate(edges, np.ones((3, 3)), iterations=1) contours, _ = cv2.findContours(dilated, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) contours = sorted(contours, key=cv2.contourArea, reverse=True)[:5] for contour in contours: peri = cv2.arcLength(contour, True) approx = cv2.approxPolyDP(contour, 0.02 * peri, True) if len(approx) == 4: area_ratio = cv2.contourArea(approx) / (image.shape[0] * image.shape[1]) if area_ratio > 0.2: return approx.reshape(4, 2) return None def four_point_transform(self, image: np.ndarray, pts: np.ndarray) -> np.ndarray: rect = self._order_points(pts) tl, tr, br, bl = rect width = int(max(np.linalg.norm(br - bl), np.linalg.norm(tr - tl))) height = int(max(np.linalg.norm(tr - br), np.linalg.norm(tl - bl))) dst = np.array([ [0, 0], [width - 1, 0], [width - 1, height - 1], [0, height - 1] ], dtype='float32') M = cv2.getPerspectiveTransform(rect.astype('float32'), dst) return cv2.warpPerspective(image, M, (width, height)) Результат: даже при наклоне до 30° текст становится горизонтальным, что радикально улучшает качество распознавания.
Что делать с тенями и бликами?
Следующая проблема — неравномерное освещение. На реальных фото часто встречаются тени от пальцев, переплёта или блики на ламинированных картах. Для теней применяем CLAHE (Contrast Limited Adaptive Histogram Equalization) в цветовом пространстве LAB. Это адаптивно выравнивает яркость по локальным областям, не создавая артефактов. Для бликов используем inpainting — обнаруживаем пересвеченные пиксели (значение >250 в одном из RGB-каналов) и интерполируем их из соседних участков.
def enhance_document(self, image: np.ndarray) -> np.ndarray: lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB) l, a, b = cv2.split(lab) clahe = cv2.createCLAHE(clipLimit=4.0, tileGridSize=(16, 16)) l_enhanced = clahe.apply(l) enhanced = cv2.merge([l_enhanced, a, b]) enhanced = cv2.cvtColor(enhanced, cv2.COLOR_LAB2BGR) kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]]) sharpened = cv2.filter2D(enhanced, -1, kernel) return sharpened Также добавляем лёгкий sharpen для компенсации размытости при съёмке с рук. Наш опыт показывает, что комбинация CLAHE + sharpen снижает CER на 3–5% по сравнению с сырым изображением.
Полный пайплайн обработки фото документа
Вот как выглядит наш production-пайплайн (код на Python с OpenCV и PaddleOCR). Функции объединены в один класс. Мы используем PaddleOCR с русским языком и угловой классификацией (use_angle_cls=True). На GPU обработка одного кадра занимает ~200 мс. Для мобильных устройств можно заменить на лёгкую модель.
Сравнение OCR-движков на реальных фото
| Движок | CER (наклон/тени) | Скорость на GPU |
|---|---|---|
| PaddleOCR | 3–7% | ~200 мс |
| Tesseract 5 | 8–15% | ~50 мс (без предобработки) |
| EasyOCR | 5–10% | ~300 мс |
PaddleOCR даёт лучший баланс точности и скорости для русскоязычных документов. При этом без нашего пайплайна предобработки любой OCR показывает на 5–10% худший CER. Используя комбинацию OpenCV и PaddleOCR, мы добиваемся CER <5% для паспортов — это в 1.5–3 раза лучше, чем без предобработки. Наш пайплайн обрабатывает кадр в 2 раза быстрее стандартных решений с аналогичным качеством.
Процесс внедрения
Реализация под ключ включает:
- Анализ: изучение типов документов, условий съёмки, требований к точности, подбор эталонных снимков.
- Проектирование: выбор стека (OpenCV, PyTorch/TensorFlow, OCR-движок), архитектура пайплайна, конфигурация контейнеров.
- Разработка: написание модулей детекции, коррекции, OCR; интеграция с backend через REST API.
- Тестирование: на вашем датасете (минимум 500 изображений) замер CER, latency p99, отладка edge-кейсов.
- Деплой: контейнеризация (Docker), развёртывание на сервере или edge-устройстве, мониторинг метрик.
Пример конфигурации PaddleOCR
ocr = PaddleOCR(use_angle_cls=True, lang='ru', use_gpu=True, det_db_thresh=0.3, det_db_box_thresh=0.5) Параметры подбираются под конкретный домен документов.
Что входит в результат
- Документированный пайплайн (код, конфиги, дашборды мониторинга).
- Интеграция через REST API с примерами запросов.
- Обучающий вебинар для команды заказчика.
- Гарантия: фиксируем целевой CER в договоре — ваш бизнес получает предсказуемое качество.
Сроки ориентировочно
| Задача | Срок |
|---|---|
| OCR с базовой предобработкой | 1–2 недели |
| Полный пайплайн с детекцией документа | 3–4 недели |
| Мобильное приложение с live preview | 5–7 недель |
Стоимость рассчитывается индивидуально после анализа вашего проекта. Свяжитесь с нами для оценки — обсудим стек и объём работ, подготовим коммерческое предложение за 1–2 дня. Получите консультацию инженера, чтобы убедиться, что решение подходит именно вам.
Мы работаем с компьютерным зрением и OCR более 5 лет, реализовали проекты для банков, страховых и государственных организаций. Ваш кейс может быть следующим.







