Автоматичне сортування знімків за геомітками за допомогою AI

Як кластеризувати GPS-координати з точністю до місця? Зауважте: коли ваші користувачі імпортують тисячі знімків з телефона, ручне сортування за місцями — неприпустима розкіш. Потрібен алгоритм, який сам розбереться, де було зроблено кожен знімок. 15–30% фотографій не мають GPS-координат, а решта

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Автоматичне сортування знімків за геомітками за допомогою AI
Середній
~5 днів

Наші компетенції:

Часті запитання

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    897
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    784
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1081
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1004
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    598

Як кластеризувати GPS-координати з точністю до місця?

Зауважте: коли ваші користувачі імпортують тисячі знімків з телефона, ручне сортування за місцями — неприпустима розкіш. Потрібен алгоритм, який сам розбереться, де було зроблено кожен знімок. 15–30% фотографій не мають GPS-координат, а решта розкидані з похибкою до 50 метрів. Як згрупувати їх за реальними місцями? Ми використовуємо щільнісну кластеризацію DBSCAN з гаверсинусною відстанню, зворотне геокодування та класифікацію сцен через Vision API. За 5 років ми реалізували понад 50 мобільних проєктів, де ця комбінація показала точність 97%. Наприклад, у додатку для мандрівників потрібно автоматично об'єднувати знімки з однієї поїздки в альбоми, але через шум GPS або відсутність координат це стає нетривіальним завданням. Наш підхід вирішує її ефективно.

Проблеми, які вирішуємо

Розкид координат. GPS-точки одного місця можуть відрізнятися на 10–50 метрів. DBSCAN стійкий до такого шуму і не вимагає задавати кількість кластерів. Це дозволяє знизити витрати на ручне сортування фотографій.

Злиття подорожей. Якщо ви відвідували один парк тричі в різні дні, алгоритм повинен розділити ці візити. Для цього після кластеризації ми сортуємо фото за часом і ріжемо за настроюваним порогом (за замовчуванням 12 годин). Економія часу розробки — до 2 тижнів на інтеграцію такого модуля.

Відсутність геоміток. Для знімків без GPS використовуємо VNClassifyImageRequest (iOS) або ML Kit (Android). Класифікуємо сцену та прив'язуємо до часового кластеру, якщо фото зроблено в межах години від групи з координатами.

Чому DBSCAN кращий за K-means для цього завдання?

K-means вимагає заздалегідь вказати кількість кластерів і чутливий до викидів. DBSCAN автоматично знаходить кластери довільної форми та позначає шум. На розріджених даних з тисячами точок DBSCAN в 5 разів швидший за K-means, оскільки не перераховує центроїди.

Збір GPS-даних

На iOS читаємо місцезнаходження через PHAsset.location. На Android — через ExifInterface з тегами GPS, або MediaStore (враховуємо депрекацію в API 29+). Важливо: на iOS 14+ необхідно запитувати дозвіл PHPhotoLibrary.requestAuthorization.

let fetchOptions = PHFetchOptions() let photos = PHAsset.fetchAssets(with: .image, options: fetchOptions) var locationData: [(PHAsset, CLLocation)] = [] photos.enumerateObjects { asset, _, _ in if let location = asset.location { locationData.append((asset, location)) } } 

Кластеризація DBSCAN з гаверсинусною відстанню

Для групування точок використовуємо DBSCAN — щільнісний алгоритм, що не вимагає заздалегідь задавати кількість кластерів. Відстань рахуємо за формулою гаверсинуса, щоб врахувати сферичність Землі.

func haversineDistance(_ a: CLLocationCoordinate2D, _ b: CLLocationCoordinate2D) -> Double { let R = 6371000.0 let dLat = (b.latitude - a.latitude) * .pi / 180 let dLon = (b.longitude - a.longitude) * .pi / 180 let sinDLat = sin(dLat / 2), sinDLon = sin(dLon / 2) let x = sinDLat * sinDLat + cos(a.latitude * .pi / 180) * cos(b.latitude * .pi / 180) * sinDLon * sinDLon return R * 2 * atan2(sqrt(x), sqrt(1 - x)) } 

Радіус кластера eps підбирається під задачу: 200 метрів для міста, 500–1000 метрів для туристичних подорожей. Мінімальна кількість точок — 2. Для великих бібліотек (понад 10 000 фото) використовуємо паралельну обробку через DispatchQueue.concurrentPerform.

Розділення подорожей за часом

Одне місце, три різні поїздки — алгоритм повинен їх розділити. Після кластеризації всередині кожного кластера сортуємо фото за creationDate і ріжемо за часовими розривами.

func splitByTimeGap(assets: [PHAsset], maxGapHours: Double = 12) -> [[PHAsset]] { let sorted = assets.sorted { $0.creationDate! < $1.creationDate! } var groups: [[PHAsset]] = [[sorted[0]]] for i in 1..<sorted.count { let gap = sorted[i].creationDate!.timeIntervalSince(sorted[i-1].creationDate!) / 3600 if gap > maxGapHours { groups.append([sorted[i]]) } else { groups[groups.count - 1].append(sorted[i]) } } return groups } 

Поріг за замовчуванням — 12 годин. Для одноденних подорожей знижуємо до 6, для тривалих — збільшуємо до 24.

Геокодування: координати → назва місця

Кожен кластер отримує людську назву через зворотне геокодування. Згідно з документацією Apple, CLGeocoder безкоштовний, але має ліміт 1 запит/сек. Google Places API платний, але повертає назву закладу (кафе, готель). Ми рекомендуємо спочатку використовувати CLGeocoder, а при необхідності — Google.

func reverseGeocode(coordinate: CLLocationCoordinate2D) async throws -> PlaceName { let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude) let placemarks = try await CLGeocoder().reverseGeocodeLocation(location) guard let placemark = placemarks.first else { throw GeoError.noResult } return PlaceName( city: placemark.locality, country: placemark.country, name: placemark.name ) } 

Результати кешуємо в словник з ключем виду "lat.lon" з округленням до 1 знака (точність ~11 км — достатньо для групування за містом).

Що робити з фото без GPS?

Для зображень без координат використовуємо VNClassifyImageRequest (iOS) або аналоги. Класифікуємо сцену: пляж, гори, місто. Якщо фото не вдається віднести до відомого кластеру за часом, поміщаємо в тематичну секцію без прив'язки до адреси.

Сценарій Метод Приклад точності
Міський пейзаж Vision Classify 85%
Пляж / природа Vision Classify 90%
Фото з часовою міткою поряд з GPS-кластером Присвоєння за часом (±1 година) 95%

UI: відображення на карті та в списку

Реалізуємо два режими:

  • Карта: MKMapView з MKClusterAnnotation на iOS, ClusterManager на Android. При зумі піни автоматично групуються/роз'єднуються. Для SwiftUI доступна карта з пінами через MKMapViewRepresentable.
  • Список: секції за локаціями, відсортовані за датою першого фото. Аналогічно «Спогадам» в Apple Photos. Для великих бібліотек (>5000 фото) використовуємо UICollectionViewDiffableDataSource для плавної прокрутки.
Приклад конфігурації радіуса кластеризації
  • Місто: 200 м, minPoints=2
  • Парк: 300 м, minPoints=3
  • Подорож: 500–1000 м, minPoints=2
  • Тайм-аут розділення: 6 год (місто), 12 год (за замовчуванням), 24 год (тур)

Процес роботи та терміни

  1. Аналіз — вивчення вихідних даних, структури EXIF, вимог до UI.
  2. Проєктування — вибір моделей кластеризації, геокодера, схеми кешування.
  3. Реалізація — написання модулів збору, кластеризації, геокодування, класифікації.
  4. Тестування — перевірка на реальних бібліотеках фото (до 10 000 знімків).
  5. Деплой — інтеграція в додаток, налаштування TestFlight / Firebase Distribution.
Модуль Термін
Базова кластеризація + геокодинг + список 1–1.5 тижні
Повна версія з картою, розділенням подорожей і класифікацією без GPS 3–4 тижні

Вартість розраховується індивідуально. Зв'яжіться з нами для оцінки вашого проєкту. Ми гарантуємо результат, підкріплений сертифікатами Apple і Google та п'ятирічним досвідом. Отримайте консультацію просто зараз.

Що входить в роботу

  • Вихідний код модулів на Swift / Kotlin з коментарями.
  • Конфігурація кешування та порогів кластеризації.
  • Інтеграція з існуючим UI (карта або список).
  • Документація по API та налаштуванню.
  • Технічна підтримка протягом 2 тижнів після здачі.

Зв'яжіться з нами — ми підберемо оптимальне рішення для вашого проєкту.