Реализация 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
    760
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    646
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1063
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    878
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    450

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

Фудтрекинг через фото — одна из самых технически насыщенных «простых» задач в мобильной AI. Пользователь ожидает: сфотографировал борщ — получил КБЖУ. На деле между этими двумя точками стоит целая цепочка: распознавание блюда, идентификация ингредиентов, оценка порции, поиск в нутриционной базе. Каждое звено добавляет погрешность.

Техническая цепочка распознавания

Правильная архитектура — не «одна модель на всё», а pipeline из нескольких специализированных шагов.

Шаг 1: детекция и классификация блюда. CoreML на iOS (модель на базе EfficientDet или YOLOv8 классификации), TFLite на Android. Для MVP — облачный API: Clarifai Food Model, Google Cloud Vision с food-тегами или специализированный Logmeal API.

Шаг 2: оценка порции. Это сложнее. Без reference object в кадре (монета, рука, стандартная тарелка) оценить граммовку почти невозможно. Два практических решения: просить пользователя указать тип тары (тарелка 20см, стакан 200мл) или использовать ARKit/ARCore для depth estimation. Depth estimation через ARKit даёт приемлемые результаты для объёмных блюд — погрешность 15–25%, что лучше, чем ручной ввод у пользователей (они обычно занижают порцию).

Шаг 3: поиск нутриционных данных. USDA FoodData Central — бесплатный API с 700 000+ продуктов. Open Food Facts — open-source база, хороша для упакованных продуктов. Для рунета критично иметь отечественные блюда: борщ, пельмени, оливье — их нет в USDA в привычном формате.

// iOS: полный pipeline распознавания
struct FoodRecognitionPipeline {

    func analyze(image: UIImage, portionContext: PortionContext?) async throws -> MealAnalysis {

        // 1. Распознавание блюда через Logmeal API
        let foodItems = try await logmealClient.recognizeFood(image: image)

        // 2. Оценка порции
        let portionEstimates: [PortionEstimate]
        if let context = portionContext {
            portionEstimates = estimatePortionFromContext(foodItems, context: context)
        } else {
            portionEstimates = try await estimatePortionWithAR(image: image)
        }

        // 3. Нутриционные данные
        let nutritionData = try await withThrowingTaskGroup(of: NutritionResult.self) { group in
            for (item, portion) in zip(foodItems, portionEstimates) {
                group.addTask {
                    try await self.fetchNutrition(food: item, grams: portion.estimatedGrams)
                }
            }
            return try await group.reduce(into: []) { $0.append($1) }
        }

        return MealAnalysis(
            items: foodItems,
            portions: portionEstimates,
            nutrition: nutritionData.aggregate(),
            confidence: foodItems.map(\.confidence).min() ?? 0
        )
    }
}

Параллельные запросы нутриционных данных через TaskGroup важны: при 3 блюдах в кадре последовательные запросы дают 3× задержку.

Составные блюда — главная сложность

Борщ на фото — это свёкла, капуста, морковь, картофель, мясо, сметана в неизвестных пропорциях. Два варианта решения:

Рецептная база. LLM или кастомная модель разбивает блюдо на ингредиенты по рецепту. Работает для стандартных блюд, плохо — для домашней кухни с вариациями.

Пользовательская корректировка. После автоматического распознавания пользователь видит предполагаемый состав и может убрать или добавить ингредиенты. Swipe-to-remove на ингредиенте, slider для граммовки. Это принципиально лучше UX, чем «точность 98%» без возможности редактирования.

// Android: UI состава блюда с редактированием
@Composable
fun MealCompositionEditor(
    items: List<FoodItem>,
    onItemRemoved: (FoodItem) -> Unit,
    onPortionChanged: (FoodItem, Float) -> Unit
) {
    LazyColumn {
        items(items, key = { it.id }) { item ->
            SwipeToDismiss(
                state = rememberDismissState { if (it == DismissValue.DismissedToStart) {
                    onItemRemoved(item); true } else false
                },
                background = { DeleteBackground() },
                dismissContent = {
                    FoodItemRow(
                        item = item,
                        onPortionChange = { grams -> onPortionChanged(item, grams) }
                    )
                }
            )
        }
    }
}

Интеграция с HealthKit и Health Connect

Записанный приём пищи должен попадать в экосистему здоровья.

// iOS: запись в HealthKit
func logMealToHealthKit(_ meal: MealAnalysis) async throws {
    let store = HKHealthStore()
    let caloriesType = HKQuantityType(.dietaryEnergyConsumed)
    let proteinType = HKQuantityType(.dietaryProtein)
    let carbsType = HKQuantityType(.dietaryCarbohydrates)
    let fatType = HKQuantityType(.dietaryFatTotal)

    let metadata: [String: Any] = [
        HKMetadataKeyFoodType: meal.primaryItem?.name ?? "Mixed Meal"
    ]

    let samples = [
        HKQuantitySample(type: caloriesType,
                        quantity: .init(unit: .kilocalorie(), doubleValue: meal.nutrition.calories),
                        start: .now, end: .now, metadata: metadata),
        HKQuantitySample(type: proteinType,
                        quantity: .init(unit: .gram(), doubleValue: meal.nutrition.protein),
                        start: .now, end: .now)
        // + carbs, fat
    ]

    try await store.save(samples)
}

Разрешения запрашиваются заранее через HKHealthStore.requestAuthorization. Распространённая ошибка — запрашивать разрешения при первом открытии приложения, до того как пользователь увидел ценность. Apple это не запрещает, но конверсия значительно выше, если запрос появляется в момент первой записи еды.

Барьеры точности и как их честно показывать

Даже хорошая модель ошибается на нестандартных блюдах, плохом освещении и необычных ракурсах. Скрывать неуверенность — ошибка. Показывать confidence score рядом с результатом — правильно:

struct NutritionDisplayView: View {
    let analysis: MealAnalysis

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            if analysis.confidence < 0.6 {
                ConfidenceWarningBanner(
                    message: "Низкая уверенность в распознавании. Проверьте состав блюда."
                )
            }
            CalorieSummaryCard(nutrition: analysis.nutrition)
            MacroBreakdownChart(nutrition: analysis.nutrition)
            IngredientList(items: analysis.items, editable: true)
        }
    }
}

Ориентиры по срокам

Базовая интеграция (один API распознавания + USDA нутриционная база + простой UI) — 1–2 недели. Полная реализация с оценкой порции через AR, составными блюдами, пользовательской корректировкой, HealthKit/Health Connect, историей питания и дневными нормами КБЖУ — 1–2 месяца.