Реализация AI-классификации фотографий в галерее мобильного приложения
Мы внедряем on-device AI-классификацию фотографий в галерею вашего мобильного приложения. Никакой загрузки фото на сервер — всё работает локально, на iPhone или Android. Это про приватность и скорость. За 5+ лет мы реализовали такие решения для десятков проектов — от стартапов до крупных медиапорталов. Apple Vision Framework и Google ML Kit — основа нашего стека.
Пользователи ожидают, что фотографии автоматически сортируются по категориям, но реализация on-device классификации сталкивается с проблемами производительности, конфиденциальности и точности. Без правильной архитектуры приложение тормозит, батарея садится, а фото остаются неотсортированными. Наш подход решает эти задачи через инкрементальную обработку, батчинг и использование встроенных нейросетевых ускорителей. Наша команда имеет 5 лет опыта в мобильной разработке и реализовала более 20 проектов с on-device ML. Экономия на облачных вычислениях может достигать значительных сумм, а данные пользователей остаются под контролем.
Как оптимизировать классификацию для больших галерей?
Ключевой вызов — не заблокировать главный поток и не перегреть устройство. Работаем через PHFetchResult с инкрементальной обработкой в DispatchQueue.global(qos: .background). Размер батча — 50 фото, между батчами — пауза 0.1 с. Это позволяет избежать CPU throttle в 3–5 раз. Vision на iOS обрабатывает фото в 2-3 раза быстрее, чем ML Kit на Android (5–15 ms против 10–30 ms).
func classifyGallery() { let fetchOptions = PHFetchOptions() fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] let allPhotos = PHAsset.fetchAssets(with: .image, options: fetchOptions) let batchSize = 50 let processingQueue = DispatchQueue(label: "photo.classification", qos: .background) processingQueue.async { var offset = 0 while offset < allPhotos.count { let batch = (offset..<min(offset + batchSize, allPhotos.count)) .map { allPhotos.object(at: $0) } self.processBatch(assets: batch) offset += batchSize Thread.sleep(forTimeInterval: 0.1) // Даём системе отдышаться } } } On-device классификация: что доступно из коробки
На iOS работает Vision framework с VNClassifyImageRequest. Не нужны сторонние модели — встроенная классификация покрывает 1000+ категорий:
import Vision func classifyPhoto(cgImage: CGImage, completion: @escaping ([String]) -> Void) { let request = VNClassifyImageRequest { request, error in guard let results = request.results as? [VNClassificationObservation] else { return } // Берём категории с confidence > 0.5 let labels = results .filter { $0.confidence > 0.5 } .map { $0.identifier } completion(labels) } try? VNImageRequestHandler(cgImage: cgImage, options: [:]).perform([request]) } Время инференса — 5–15 ms на фото. На iPhone 13+ Neural Engine обрабатывает всю галерею в 1000 фото за ~15–20 секунд.
На Android: ML Kit ImageLabeler с ImageLabelerOptions:
val labeler = ImageLabeling.getClient( ImageLabelerOptions.Builder() .setConfidenceThreshold(0.5f) .build() ) labeler.process(InputImage.fromBitmap(bitmap, 0)) .addOnSuccessListener { labels -> val categories = labels.map { it.text } // "Dog", "Outdoor", "Sky", "Food", etc. } ML Kit поддерживает 400+ категорий без сети.
Сравнение iOS и Android
| Параметр | iOS (Vision) | Android (ML Kit) |
|---|---|---|
| Количество категорий | 1000+ | 400+ |
| Инференс на фото | 5–15 ms | 10–30 ms |
| Кастомные модели | CoreML | TensorFlow Lite |
| Фоновая обработка | DispatchQueue | Coroutines + WorkManager |
Сравнение on-device и серверной классификации
| Параметр | On-device | Серверная |
|---|---|---|
| Приватность | Данные на устройстве | Передача фото на сервер |
| Задержка | Мгновенно | 1–5 сек с учётом сети |
| Стоимость инфраструктуры | Нет | Затраты на GPU/API |
| Работа офлайн | Да | Нет |
Почему on-device ML безопаснее чем облачные решения?
Серверная классификация требует передачи фото, задержки на сеть и затрат на инфраструктуру. On-device подход работает офлайн, мгновенно и безопасно. Мы гарантируем, что пользовательские данные не покидают устройство.
Какие инструменты нужны для кастомных категорий?
Встроенный Vision не всегда покрывает все нужные категории. Для кастомных (например, «рецепт», «скриншот документа», «чек», «виза») — обучаем CreateML модель:
let dataSource = MLImageClassifier.DataSource.labeledDirectories(at: trainingDir) let model = try MLImageClassifier(trainingData: dataSource) try model.write(to: modelURL) Точность на кастомных категориях при 20+ примерах — 85–95%. Модель в CoreML формате — 5–15 MB. Можно доставлять через Core ML Model Deployment без обновления приложения.
Хранение результатов классификации
Результаты сохраняем локально — не на сервер. Core Data с NSPersistentContainer:
// Entity: PhotoClassification // Attributes: assetLocalIdentifier (String), labels (Transformable: [String]), classifiedAt (Date) Индекс на assetLocalIdentifier + индекс на labels для быстрого поиска. При 50k фото таблица весит ~5–10 MB.
Типичные ошибки
- Classifying на main thread — самое частое.
VNImageRequestHandler.performвыполняется синхронно. Всегда в background queue. - Запрашивать full-resolution для классификации — лишнее. PHAsset requestImage с
targetSize: CGSize(width: 224, height: 224)достаточно. - Не обновлять классификации при изменении галереи —
PHPhotoLibraryChangeObserverдолжен запускать инкрементальную обработку только для новых/изменённых фото.
Что входит в работу
- Разработка on-device классификации (Vision / ML Kit)
- Интеграция кастомных моделей CoreML / TFLite
- Инкрементальная обработка галереи с батчингом
- Хранение результатов в CoreData / Room
- Тестирование на устройствах (iOS 16+ / Android 12+)
- Документация и обучение команды
- Поддержка после релиза (2 недели)
Сроки и стоимость
Базовая классификация с Vision + хранение в Core Data — 4–6 дней. Полная реализация с кастомными категориями, инкрементальными обновлениями и быстрым поиском по тегам — 2–3 недели. Стоимость рассчитывается индивидуально после аудита вашего проекта.
Закажите разработку AI-галереи — получите консультацию по вашему проекту. Свяжитесь с нами, чтобы оценить возможности для вашего приложения.







