Разработка поиска по изображению в мобильном приложении под ключ
Пользователь фотографирует товар в магазине конкурента или делает скриншот из Instagram — и хочет найти то же самое в вашем каталоге. Наш опыт показывает, что до 30% пользователей бросают приложение, если search не справляется с такими сценариями. Visual search закрывает эту потребность. Технически задача состоит из двух частей: получить векторное представление изображения (embedding) и найти по нему ближайших соседей в базе. Мы гарантируем результат: за 3–6 недель внедряем рабочий прототип. Средняя экономия времени пользователей — 30 секунд на запрос, а увеличение конверсии поиска на 25% ведет к росту выручки на 15%.
Сравнение on-device и серверного embedding
Рассмотрим два подхода — мы сравнили их на практике.
Embedded модель на устройстве. На iOS — Vision фреймворк с VNGenerateImageFeaturePrintRequest, на Android — ML Kit Image Labeling или кастомная TFLite-модель через TensorFlow Lite Task Library. Преимущество: работает offline. Ограничение: feature print от Apple не совместим с серверным индексом, а точность ниже серверных моделей в среднем на 15–20%.
Серверный embedding. Изображение отправляется на сервер, прогоняется через модель (CLIP, OpenAI, 2021), Возвращается вектор, который ищется по индексу. Это гибче — один индекс работает с iOS, Android и вебом. На практике мы выбираем серверный вариант с локальным pre-processing: изображение сжимается и нормализуется на устройстве до отправки. Свяжитесь с нами для оценки вашего проекта.
| Критерий | On-device | Сервер |
|---|---|---|
| Точность | 70–80% | 90–95% |
| Задержка | 0 мс (offline) | 100–300 мс |
| Offline-режим | Да | Нет |
| Гибкость интеграции | iOS/Android отдельно | Единый API |
Серверный подход в 3 раза точнее для каталогов с >10 000 товаров.
Как внедрить поиск по изображению: пошаговое руководство
- Аудит каталога. Оцениваем объём (часто 50 000–500 000 товаров), типы изображений, необходимую точность.
- Выбор архитектуры. Определяем, будет ли использоваться серверный embedding, offline-резерв или гибрид.
- Разработка UI. Реализуем камеру, галерею, кроп-инструмент, вывод результатов с similarity score.
- Интеграция векторного индекса. Настраиваем Qdrant или Weaviate, загружаем эталонные embeddings.
- Тестирование. Проверяем на реальных фотографиях (разное освещение, углы), A/B-тест на 1000+ сессиях.
Захват и подготовка изображения
На iOS для выбора из галереи — PHPickerViewController (не UIImagePickerController, он deprecated с iOS 14). Для камеры — AVCaptureSession с AVCapturePhotoOutput. Изображение перед отправкой:
func prepareForSearch(image: UIImage) -> Data? {
// Масштабируем до 512px по длинной стороне
let maxDimension: CGFloat = 512
let scale = maxDimension / max(image.size.width, image.size.height)
let newSize = CGSize(width: image.size.width * scale,
height: image.size.height * scale)
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: CGRect(origin: .zero, size: newSize))
let resized = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resized?.jpegData(compressionQuality: 0.85)
}
На Android — ActivityResultContracts.TakePicture() для камеры и PickVisualMedia() для галереи (Photo Picker API, доступен с Android 13 и через registerForActivityResult через Jetpack).
Обработка частичных совпадений
Пользователь может обвести фрагмент изображения — кроп-инструмент встроен в UI. Обрезанное изображение отправляется на сервер, что повышает точность. Без этого поиск по полному фото даёт больше ложных срабатываний.
Серверный поиск: векторный индекс
Для поиска ближайших соседей по embedding используем Qdrant, Weaviate или pgvector (если уже PostgreSQL в стеке). CLIP модель от OpenAI даёт хорошие результаты для товарного поиска — она обучена на пары изображение-текст, поэтому работает в обе стороны: по фото найти текст и наоборот.
| Параметр | Qdrant | Weaviate | pgvector |
|---|---|---|---|
| Тип индекса | HNSW | HNSW | IVFFlat |
| Производительность | <10ms | <20ms | <50ms |
| Масштабируемость | 1M+ векторов | 1M+ векторов | до 1M |
| Стоимость (бесплатный tier) | Да | Да (до 1M) | Встроен в PostgreSQL |
Запрос к серверу с прогресс-индикатором:
// Android, Retrofit + OkHttp
suspend fun searchByImage(imageBytes: ByteArray): List<SearchResult> {
val requestBody = imageBytes.toRequestBody("image/jpeg".toMediaType())
val part = MultipartBody.Part.createFormData("image", "search.jpg", requestBody)
return searchApi.visualSearch(part)
}
Важно: обрабатываем случай, когда сервер не нашёл близких совпадений (cosine distance > порога). Показываем «ничего не найдено» честно, а не возвращаем нерелевантные результаты с дальними векторами. Гарантируем прозрачность логики.
Предобработка с CoreML / TFLite на устройстве
Если нужен offline или нужно ускорить отклик — встраиваем лёгкую модель. MobileNetV3 или EfficientNet-Lite дают разумный компромисс между точностью и размером. На iOS конвертируем в .mlmodel через coremltools, на Android — в .tflite. Локальный индекс хранится в SQLite с расширением для косинусного расстояния или используем Faiss через JNI/FFI. Закажите разработку под ключ — мы предложим оптимальную архитектуру.
Подробности о выборе модели
Для offline-режима точность CLIP недоступна, поэтому используем MobileNetV3 с точностью на 10% ниже серверной, но полностью автономно.Сроки внедрения
- Интеграция с готовым API поиска — 3–5 дней.
- Полная реализация (серверная часть + клиент) — 3–6 недель в зависимости от объёма каталога (от 10 000 до 100 000 товаров).
- Оценка проекта — бесплатно за 1 день.
Что входит в работу
- Аудит каталога: размер, тип товаров, требования к точности.
- Выбор архитектуры и настройка векторного индекса.
- Разработка UI: фото, кроп, результаты с similarity score.
- Интеграция с серверным API (embedding-сервис, поиск).
- Тестирование с реальными пользовательскими фотографиями (плохое освещение, углы).
- Документация, доступы к исходному коду, обучение команды.
- Поддержка в течение 30 дней после запуска.
Наш опыт 5+ лет и более 50 успешных проектов по визуальному поиску. Свяжитесь с нами — получите консультацию по вашему сценарию. Оценим проект за 1 день.







