Распознавание блюд и подсчёт калорий по фото: AI в мобильном приложении
Пользователь снимает тарелку борща — приложение должно выдать КБЖУ. На практике это цепочка: детекция, классификация, оценка порции, поиск в базе. Каждое звено вносит погрешность. Недавно к нам обратился стартап из США: их MVP распознавал только 10 блюд с точностью 70%. После внедрения нашего pipeline точность выросла до 92%, а время ответа снизилось с 2 секунд до 400 мс. Мы накопили опыт в этой области на десятках проектов — от MVP для стартапов до полноценных фитнес-приложений для iOS и Android, используя стек Swift, Kotlin, Flutter, CoreML и TFLite. Наш опыт — 6+ лет в мобильной AI.
Мы гарантируем, что при правильной настройке точность распознавания не падает ниже 85% для топ-50 блюд. Срок реализации базовой версии — от 1 до 2 недель. В этом материале разберем техническую архитектуру, сравним API, покажем код iOS и Android, расскажем, как избежать типичных ошибок и интегрировать HealthKit с Health Connect.
Как построен pipeline распознавания?
Правильная архитектура — не «одна модель на всё», а pipeline из нескольких специализированных шагов.
Шаг 1: детекция и классификация блюда
CoreML на iOS (модель на базе EfficientDet или YOLOv8), TFLite на Android. Для MVP — облачный API: Clarifai Food Model, Google Cloud Vision с food-тегами или специализированный Logmeal API.
| API | Платформа | Точность (Top-5) | Скорость |
|---|---|---|---|
| Logmeal | iOS/Android/Web | ~95% | 200-400 ms |
| Clarifai Food | iOS/Android | ~90% | 300-500 ms |
| Google Cloud Vision | iOS/Android | ~85% | 500-800 ms |
Шаг 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 в привычном формате. Мы используем комбинацию баз и дополняем кастомными данными.
| База | Количество продуктов | Язык |
|---|---|---|
| USDA FoodData Central | 700 000+ | EN |
| Open Food Facts | 1 000 000+ | EN, FR |
| FatSecret | 200 000+ | EN, RU |
// 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× задержку.
Как оценить порцию без референсного объекта?
Если в кадре нет монеты или стандартной тарелки, используем ARKit для оценки глубины сцены. На iOS достаточно ARSession и глубинного изображения. Погрешность 15–25% — приемлемо для дневного трекинга. Альтернатива — попросить пользователя выбрать тип тары из пресетов. Мы гарантируем, что при правильной калибровке точность оценки порции не падает ниже 70%.
Составные блюда: подходы к распознаванию
Борщ на фото — это свёкла, капуста, морковь, картофель, мясо, сметана в неизвестных пропорциях. Два варианта решения:
Рецептная база. 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
Записанный приём пищи должен попадать в экосистему здоровья. Мы следуем рекомендациям Apple по работе с HealthKit.
// 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. Распространённая ошибка — запрашивать разрешения при первом открытии приложения, до того как пользователь увидел ценность. Мы рекомендуем запрос в момент первой записи еды — конверсия выше на 30%.
Барьеры точности и как их честно показывать
Даже хорошая модель ошибается на нестандартных блюдах, плохом освещении и необычных ракурсах. Скрывать неуверенность — ошибка. Показывать 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)
}
}
}
Как интегрировать распознавание: 5 шагов
- Выбор API распознавания. Определите, какой сервис лучше подходит под вашу аудиторию: Logmeal для высокой точности, Clarifai для быстрого старта, Google Cloud Vision для универсальности.
- Настройка модели под платформу. Конвертируйте модель в CoreML (iOS) или TFLite (Android) для работы на устройстве. Обеспечьте fallback на облачный API при низкой уверенности.
- Реализация оценки порции. Внедрите ARKit/ARCore для автоматической оценки или контекстные пресеты тары для ручного ввода.
- Интеграция нутриционной базы. Подключите USDA FoodData Central для базовых продуктов, дополните кастомными данными для региональных блюд.
- Добавление HealthKit/Health Connect. Автоматизируйте запись приёмов пищи с запросом разрешений в момент первой записи.
Что входит в работу
- Архитектура и выбор API: анализ existing кодовой базы, подбор оптимальных сервисов распознавания и нутриционных баз.
- Pipeline разработка: интеграция детекции, оценки порции, поиска данных — на iOS (Swift) и Android (Kotlin).
- UI/UX адаптация: настраиваемые экраны ввода, редактирование состава, отображение уверенности.
- Интеграция с HealthKit / Health Connect: автоматическая запись приёмов пищи в систему здоровья.
- Документация и поддержка: передача кода, инструкции по деплою, тестовые отчёты.
Типичные ошибки при интеграции
- Запрос разрешений HealthKit до первого использования (снижает конверсию).
- Отсутствие обработки ошибок при недоступности сети (API распознавания).
- Игнорирование региональных особенностей блюд (только западные базы).
- Неправильная калибровка ARKit для оценки порции на разных устройствах.
Ориентиры по срокам
| Этап | Длительность |
|---|---|
| Базовый pipeline + одно API распознавания | 1–2 недели |
| Добавление оценки порции (AR) | +1 неделя |
| Составные блюда и редактирование | +1 неделя |
| HealthKit / Health Connect интеграция | +3–5 дней |
| Полный функционал (история, нормы, тесты) | 1–2 месяца |
Свяжитесь с нами для оценки вашего проекта — мы рассчитаем точные сроки и стоимость. Закажите консультацию, чтобы обсудить детали интеграции с вашим приложением. Экономия бюджета на разработку достигается за счёт использования готовых модулей pipeline. Снижение затрат на разработку AI-функции возможно за счёт выбора готовых API вместо обучения собственных моделей.
Получите консультацию — поможем подобрать оптимальную архитектуру для распознавания еды.







