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

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

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Реализация AI-группировки фотографий по лицам в мобильном приложении
Сложная
~1-2 недели
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • 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-группировки фотографий по лицам в мобильном приложении

Группировка по лицам — это распознавание, что одна и та же личность встречается на разных фотографиях, без идентификации (кто этот человек). Технически: детекция лица → извлечение эмбеддинга (числовой вектор 128–512 измерений) → кластеризация по сходству векторов. Google Photos делает это on-device именно так.

On-device vs Server: осознанный выбор

Для этой задачи on-device — не просто удобно, это требование регуляторов в ряде юрисдикций. Биометрические данные (а face embeddings технически считаются биометрией) нельзя передавать без явного согласия по GDPR и ряду национальных законов. Рекомендую строить on-device пайплайн с нулевой передачей на сервер.

Пайплайн: детекция → эмбеддинг → кластеризация

Детекция лиц

// iOS: VNDetectFaceRectanglesRequest
let request = VNDetectFaceRectanglesRequest { req, _ in
    guard let faces = req.results as? [VNFaceObservation], !faces.isEmpty else { return }
    for face in faces {
        let faceRect = VNImageRectForNormalizedRect(face.boundingBox, width, height)
        self.extractEmbedding(from: originalImage.cropping(to: faceRect)!)
    }
}

На Android: ML Kit FaceDetector или MediaPipe FaceDetector. ML Kit проще интегрируется, MediaPipe даёт больше контроля.

Извлечение эмбеддинга

Apple не предоставляет встроенный face recognition API (только detection). Используем MobileFaceNet — компактная модель (1–3 MB) для face embeddings, работает on-device через Core ML:

// Извлечение 128-мерного эмбеддинга
func extractEmbedding(from faceImage: CGImage) -> [Float]? {
    guard let input = try? MobileFaceNetInput(face_image: MLMultiArray(from: resize(faceImage, to: CGSize(width: 112, height: 112)))) else { return nil }
    guard let output = try? facenetModel.prediction(input: input) else { return nil }
    // Нормализуем вектор (L2 norm)
    let embedding = (0..<128).map { output.embedding[$0].floatValue }
    return l2Normalize(embedding)
}

func l2Normalize(_ v: [Float]) -> [Float] {
    let norm = sqrt(v.reduce(0) { $0 + $1 * $1 })
    return norm > 0 ? v.map { $0 / norm } : v
}

После L2-нормализации косинусное расстояние между эмбеддингами одного человека — <0.3, разных людей — >0.6. Порог 0.4–0.5 хорошо работает на практике.

Кластеризация

Для кластеризации без заранее известного числа кластеров — DBSCAN. В Swift нет встроенной реализации, пишем сами или используем Accelerate/BLAS:

// Упрощённый DBSCAN для face clustering
func dbscan(embeddings: [[Float]], eps: Float = 0.45, minPoints: Int = 2) -> [Int] {
    var labels = Array(repeating: -1, count: embeddings.count)  // -1 = noise
    var clusterId = 0

    for i in 0..<embeddings.count {
        guard labels[i] == -1 else { continue }
        let neighbours = rangeQuery(embeddings: embeddings, idx: i, eps: eps)
        if neighbours.count < minPoints { continue }  // noise point

        labels[i] = clusterId
        var seeds = neighbours
        while !seeds.isEmpty {
            let q = seeds.removeFirst()
            if labels[q] == -1 { labels[q] = clusterId }
            if labels[q] != clusterId { continue }
            labels[q] = clusterId
            let qNeighbours = rangeQuery(embeddings: embeddings, idx: q, eps: eps)
            if qNeighbours.count >= minPoints { seeds.append(contentsOf: qNeighbours) }
        }
        clusterId += 1
    }
    return labels
}

Cosine distance через Accelerate vDSP_dotpr — быстро даже для 10k векторов.

Производительность на больших галереях

Реальная галерея — 5000–50000 фото. Из них лица есть примерно в 30–40%. Пусть 10000 фото с лицами, по 2 лица в среднем = 20000 эмбеддингов.

DBSCAN с O(n²) на 20k векторов 128 измерений — ~10–30 секунд на iPhone 14. Ускорение: предварительный ANN (Approximate Nearest Neighbour) через FAISS (есть Swift binding) сокращает до O(n log n).

Обработку запускаем в фоне через BackgroundTask (iOS 13+, BGProcessingTask) — задача может работать несколько минут, пока устройство заряжается.

BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.app.faceGrouping") { task in
    let bgTask = task as! BGProcessingTask
    self.runFaceGrouping(completion: { bgTask.setTaskCompleted(success: true) })
    bgTask.expirationHandler = { /* save progress */ }
}

Хранение результатов

Хранить сами эмбеддинги нельзя в iCloud/CloudKit без явного согласия (биометрия). Локально — в Core Data, зашифрованном через Data Protection API (fileProtection = .complete). Identifier для маппинга — PHAsset.localIdentifier, не исходное фото.

Сроки

On-device пайплайн с детекцией, эмбеддингами и кластеризацией для средних галерей — 2–3 недели. Масштабируемая реализация с FAISS, фоновой обработкой, инкрементальными обновлениями и UI — 4–5 недель. Стоимость рассчитывается индивидуально.