Реализация сканирования документов через камеру мобильного приложения
Пользователь держит телефон над договором, приложение само находит края листа, выравнивает перспективу и отдаёт чистый PDF. Это не «сфотографировать и обрезать» — там внутри детектор контуров, гомографическая трансформация и пост-обработка. Каждый шаг можно испортить.
Где ломается чаще всего
Детектор краёв ломается на бликах и тенях
VNDetectRectanglesRequest (iOS Vision) возвращает VNRectangleObservation с четырьмя corner points в нормализованных координатах. Проблема: на глянцевой бумаге под прямым светом алгоритм путает блик с краем листа. Решение — перед детекцией применяем CIFilter с CIColorControls (уменьшаем inputSaturation) и CIHighlightShadowAdjust. Это убирает блики как артефакты цвета.
На Android Vision API (com.google.android.gms:play-services-mlkit-document-scanner) справляется лучше с тенями, но требует Google Play Services. Альтернатива без зависимости от GMS — OpenCV findContours + approxPolyDP с фильтром по площади и соотношению сторон. Порог minArea = 30% от площади кадра отсекает фоновые объекты.
Коррекция перспективы
После получения четырёх точек применяем perspective transform. iOS: CIPerspectiveCorrection с явной передачей inputTopLeft, inputTopRight, inputBottomLeft, inputBottomRight в координатах изображения (не превью). Частая ошибка — использовать координаты превью-слоя напрямую без пересчёта через VNImagePointForNormalizedPoint.
Android: getPerspectiveTransform + warpPerspective из OpenCV или матричная трансформация через android.graphics.Matrix.setPolyToPoly. Второй вариант работает без OpenCV, но ограничен аффинными преобразованиями — для сильного перспективного искажения не подходит.
Flutter: пакет cunning_document_scanner (обёртка над нативными SDK) или собственная реализация через image + ручной расчёт гомографии на Dart. Последнее — трудоёмко, проще нативный channel.
Постобработка: читаемость важнее красоты
После выпрямления документ нужно обработать для читаемости при распечатке или OCR:
-
Адаптивная бинаризация —
cv::adaptiveThresholdс методом Gaussian лучше чем Otsu на документах с неравномерной подсветкой - Deskew — если документ повёрнут на 1-2° после трансформации, Hough Lines находят наклон текстовых строк и корректируют
-
Резкость —
CISharpenLuminance(iOS) илиSharpnessfilter (Android) с умеренным значением (0.4-0.6), не больше
Цветовые режимы стоит дать пользователю: «Авто», «Документ» (чёрно-белый), «Фото» (полный цвет). В режиме «Документ» — бинаризация. В «Авто» — анализ гистограммы: если документ содержит <5% насыщенных пикселей, применяем монохромную обработку.
Многостраничный скан и PDF
Собираем UIImage[] / Bitmap[], экспортируем через PDFKit (iOS 11+) или android.graphics.pdf.PdfDocument. На Flutter — пакет pdf (pub.dev). Размер PDF оптимизируем: JPEG compression 85% достаточно для читаемости, при этом страница A4 занимает ~150-250 КБ против 2-4 МБ PNG.
Превью в реальном времени: показываем контур поверх AVCaptureVideoPreviewLayer / PreviewView через CAShapeLayer / SurfaceView. Обновляем контур раз в 3-5 кадров (не на каждый!) — иначе детектор съедает CPU и превью тормозит.
Как строим работу
Аудит требований → выбор SDK (нативный Vision/ML Kit vs OpenCV) → интеграция превью с оверлеем → коррекция + постобработка → экспорт PDF → тестирование на 10+ типах документов (паспорт, договор, квитанция, книжный разворот).
Сроки: от 3 до 5 рабочих дней в зависимости от платформы и требований к качеству. Если нужна интеграция с OCR-распознаванием — закладываем ещё 2-3 дня.







