Розпізнавання страв та підрахунок калорій по фото: AI у мобільному додатку
Користувач фотографує тарілку борщу — додаток має видати КБЖУ. На практиці це ланцюжок: детекція, класифікація, оцінка порції, пошук у базі. Кожна ланка вносить похибку. Нещодавно до нас звернувся стартап із США: їх MVP розпізнавав лише 10 страв з точністю 70%. Після впровадження нашого pipeline точність зросла до 92%, а час відповіді знизився з 2 секунд до 400 мс. Ми накопичили досвід у цій галузі на десятках проєктів — від MVP для стартапів до повноцінних фітнес-додатків для iOS та Android, використовуючи стек Swift, Kotlin, Flutter, CoreML та TFLite. Наш досвід — 10+ років у мобільній 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, UA |
// 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 замість навчання власних моделей.
Отримайте консультацію — допоможемо підібрати оптимальну архітектуру для розпізнавання їжі.







