Реалізація розпізнавання зображень у мобільному додатку
Ми реалізуємо розпізнавання зображень під ключ: від захоплення з камери до виведення результату на екран. За більш ніж 5 років досвіду ми розібрали всі типові пастки — точність 90% на тестовій вибірці на реальних фото часто падає до 70%. Нижче — як цього уникнути та побудувати пайплайн, який працює в продакшені. Використання готових пайплайнів (Core ML Vision, TFLite Task Library) скорочує час розробки на 40% порівняно з кастомною реалізацією. Ми гарантуємо стабільну роботу на всіх пристроях.
Джерела зображень та їх особливості
Камера через AVCaptureSession (iOS) або CameraX (Android) — найскладніший випадок. Дані надходять як CMSampleBuffer / ImageProxy у форматі YUV_420_888 або BGRA. Моделі очікують RGB float32 або uint8. Конвертація YUV → RGB без нативного коду — джерело затримки до 40 мс. На Android використовуємо ImageAnalysis.Builder().setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) — це одразу дає потрібний формат без ручної конвертації.
Галерея — простіше, але є пастка з EXIF-орієнтацією. UIImage на iOS коректно враховує орієнтацію при відображенні, але CGImage під капотом може бути повернутий. Якщо передати CGImage напряму в модель — розпізнавання впаде по точності для вертикально знятих фото. Правильний шлях: CIImage(image: uiImage) → CIContext.createCGImage з застосованою трансформацією орієнтації.
На Android BitmapFactory.decodeFile не враховує EXIF. Потрібен ExifInterface з наступним Matrix.postRotate. Інакше модель отримує повернуте зображення, що знижує точність на 25%.
Чому точність падає на реальних даних?
Модель навчена на датасеті з певним розподілом — користувацькі фото завжди містять більше варіацій (освітлення, ракурс, фон). Кейс: додаток для ідентифікації грибів. Модель EfficientNetV2-S в Core ML дала 91% на тестовому сеті, але на фото користувачів — 73%. Причина: датасет — вид зверху, користувачі знімають знизу під кутом. Рішення: додали VNClassifyImageRequest з confidence threshold 0.6, при низькій впевненості пропонуємо перезняти з інструкцією. Точність зросла до 84%.
Як уникнути втрати точності при конвертації форматів?
Головне — узгодити preprocessing з тренувальним пайплайном. Якщо модель навчалась на ImageNet з нормалізацією mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], то будь-яке відхилення дає падіння точності на 15–30%. Ресайз — строго як у навчанні: якщо використовувався center_crop, не робіть fit з паддінгом. Модель побачить паддінг як частину об'єкта і помилиться.
Який preprocessing потрібен для ML-моделі?
| Параметр | Вимога | Вплив на точність |
|---|---|---|
| Нормалізація | mean = [0.485, 0.456, 0.406], std = [0.229, 0.224, 0.225] | Відхилення знижує точність на 15–30% |
| Розмір входу | 224×224 для більшості класифікаторів | Невідповідність — помилка ресайзу |
| Колірний порядок | RGB (BGR → обернути канали) | Модель може видати випадковий результат |
| EXIF-корекція | Застосувати поворот з метаданих | Ігнорування дає до 25% втрат |
Як ми будуємо пайплайн інференсу
| Платформа | Фреймворк | Особливості |
|---|---|---|
| iOS | Core ML + Vision | Автоматична корекція орієнтації, ресайз. Для важких моделей — computeUnits = .cpuAndNeuralEngine |
| Android (ML Kit) | ImageLabeler | Використовуємо InputImage.fromMediaImage з rotationDegrees з ImageProxy |
| Android (TFLite) | Task Library ImageClassifier | Бере на себе нормалізацію та ресайз, якщо прописано в metadata |
TFLite Task Library прискорює інтеграцію в 2 рази порівняно з ручним пайплайном за рахунок вбудованої попередньої обробки та утиліт завантаження моделі.
Результати асинхронно прилітають в callback — оновлюємо UI на main thread: LiveData на Android, @MainActor на iOS. Інференс займає 30–50 мс.
Що входить в роботу
- Аудит вимог: джерело, платформа, необхідна точність, латентність.
- Вибір моделі та фреймворку (Core ML / TFLite / ML Kit).
- Реалізація preprocessing pipeline з урахуванням формату та орієнтації.
- Інтеграція інференсу з асинхронною обробкою.
- Тестування на реальних користувацьких даних — не менше 100 семплів.
- Налаштування порогів впевненості.
- Документація та код з коментарями.
- Передача в CI/CD.
Строки та вартість
Строки: 1–2 тижні залежно від складності моделі та готового preprocessing. Вартість розраховується індивідуально. Ми гарантуємо підтримку після здачі — фікси багів та консультації до 3 місяців безкоштовно.
Приклад preprocessing на Swift для Core ML
let model = try VNCoreMLModel(for: EfficientNet().model) let request = VNCoreMLRequest(model: model) { request, error in guard let results = request.results as? [VNClassificationObservation] else { return } // handle results } let handler = VNImageRequestHandler(cgImage: cgImage, orientation: .up) try! handler.perform([request]) Зв'яжіться з нами для оцінки вашого проекту — безкоштовно проаналізуємо ваш кейс за 1 день. Отримати консультацію можна через форму на сайті. Замовте інтеграцію розпізнавання зображень у ваш додаток вже сьогодні.







