Розробка пошуку за зображенням у мобільному додатку під ключ
Користувач фотографує товар у магазині конкурента або робить скріншот з 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 день.







