Реализация AI-группировки фотографий по локациям в мобильном приложении

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.
Разработка и поддержка любых видов мобильных приложений:
Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Реализация AI-группировки фотографий по локациям в мобильном приложении
Средняя
~5 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1054
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    874
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    445

Реализация AI-группировки фотографий по локациям в мобильном приложении

Группировка по локациям кажется простой — у каждого фото есть GPS. Но реальная задача сложнее: координаты с разбросом 10–50 метров нужно склеить в «место» (кафе, парк, пляж), разные поездки в одно место — разделить по времени, а тысячи фото без GPS — отнести к локации по контексту.

Шаг 1: CLLocation clustering

Большинство фото с современных смартфонов содержат GPS в EXIF. На iOS читаем через PHAsset.location:

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))
    }
}

Для Android: ExifInterface с TAG_GPS_LATITUDE / TAG_GPS_LONGITUDE, или MediaStore MediaColumns.LATITUDE (deprecated в API 29+, теперь через ContentResolver query с MediaStore.Images.Media.LATITUDE).

Кластеризация GPS-координат — снова 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 метров.

Разделение по времени: одно место, разные поездки

Пользователь бывал в Барселоне трижды. GPS-кластер один, но визиты — разные. Нужно разбить по временным промежуткам внутри кластера:

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 часа.

Геокодирование: координаты → название места

У нас кластер с центроидом (lat, lon). Нужно человеческое название: «Барселона, Испания» или «Центральный парк, Нью-Йорк».

Apple MapKitCLGeocoder().reverseGeocodeLocation(). Бесплатно, но лимиты для пакетных запросов. Не превышать 1 запрос в секунду.

Google Places API — платно, но даёт название заведения (кафе, отель), а не только улицу:

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
    )
}

Кешируем результаты геокодирования — одни и те же координаты могут встречаться у сотен фото. Словарь [String: PlaceName] с ключом "\(lat.1)_\(lon.1)" (округление до 1 знака ≈ 11 км, достаточно для группировки по городу).

Фото без GPS: визуальная классификация

15–30% фото не содержат GPS (старые фото, съёмка в помещении при отключённой геолокации). Для них — Vision VNClassifyImageRequest + словарь категорий с геосемантикой.

Если фото классифицировано как «beach», «mountain», «cityscape» — показываем в секции «Природа» или «Города» без конкретного адреса. Если есть временная метка и рядом есть другие фото с GPS — присваиваем ближайший кластер по времени (+/- 1 час).

UI: отображение

Два паттерна для UI:

  • Map-based: MKMapView с кластерными пинами. Тап на пин — галерея локации
  • List-based: сортировка по дате, секции = локации. Как в Apple Photos «Воспоминания»

Для map-based: MKClusterAnnotation на iOS нативно поддерживает clustering пинов при zoom-out. На Android — Google Maps SDK ClusterManager.

Сроки

GPS-кластеризация с геокодированием и базовым UI — 1–1.5 недели. Полная реализация с разделением по поездкам, визуальной группировкой фото без GPS и картой — 3–4 недели. Стоимость рассчитывается индивидуально.