זיהוי מזון וספירת קלוריות מתמונות: AI באפליקציות מובייל
משתמש מצלם קערת בורשט—האפליקציה חייבת להציג את הערכים התזונתיים. בפועל, מדובר בשרשרת: זיהוי, סיווג, הערכת מנה, חיפוש במאגר נתונים. כל חוליה מוסיפה שגיאה. לאחרונה, סטארטאפ אמריקאי פנה אלינו: ה-MVP שלהם זיהה רק 10 מנות בדיוק של 70%. לאחר הטמעת הפייפרליין שלנו, הדיוק עלה ל-92%, וזמן התגובה ירד מ-2 שניות ל-400 אלפיות השנייה. צברנו ניסיון בתחום זה בעשרות פרויקטים—מ-MVPs לסטארטאפים ועד אפליקציות כושר מלאות ל-iOS ואנדרואיד, באמצעות Swift, Kotlin, Flutter, CoreML ו-TFLite. רקורד העבודה שלנו: 10+ שנים ב-AI למובייל, 40+ פרויקטים שהושלמו.
בתצורה נכונה, דיוק הזיהוי נשאר מעל 85% עבור 50 המנות המובילות. זמן אספקה לגרסה בסיסית: 1 עד 2 שבועות. במאמר זה, אנו מפרקים את הארכיטקטורה הטכנית, משווים APIs, מציגים קוד ל-iOS ואנדרואיד, מסבירים כיצד להימנע ממלכודות נפוצות, ומשלבים HealthKit עם Health Connect.
כיצד בנוי הפייפרליין?
הארכיטקטורה הנכונה אינה "מודל אחד לשלוט בכולם"—אלא פייפרליין של שלבים מתמחים.
שלב 1: זיהוי וסיווג
CoreML ב-iOS (מודל המבוסס על EfficientDet או YOLOv8), TFLite באנדרואיד. עבור MVP, APIs בענן הם אפשרות viable: Clarifai Food Model, Google Cloud Vision עם תגיות מזון, או ה-API הייעודי Logmeal.
| API | פלטפורמה | דיוק (Top-5) | מהירות |
|---|---|---|---|
| Logmeal | iOS/אנדרואיד/Web | ~95% | 200–400 אלפיות השנייה |
| Clarifai Food | iOS/אנדרואיד | ~90% | 300–500 אלפיות השנייה |
| Google Cloud Vision | iOS/אנדרואיד | ~85% | 500–800 אלפיות השנייה |
שלב 2: הערכת מנה
זה קשה יותר. ללא אובייקט ייחוס בפריים (מטבע, יד, צלחת סטנדרטית), הערכת גרמים היא כמעט בלתי אפשרית. שני פתרונות מעשיים: לבקש מהמשתמש לציין את סוג המיכל (צלחת 20 ס"מ, כוס 200 מ"ל) או להשתמש ב-ARKit/ARCore להערכת עומק. הערכת עומק באמצעות ARKit נותנת תוצאות מקובלות למנות נפחיות—מרווח שגיאה של 15–25%, שעדיף על קלט ידני של המשתמש (שבדרך כלל ממעיט בערך).
שלב 3: חיפוש נתונים תזונתיים
USDA FoodData Central הוא API חינמי עם 700,000+ מוצרים. Open Food Facts הוא מאגר נתונים בקוד פתוח, טוב למזון ארוז. לשווקים דוברי רוסית, קריטי שיהיו מנות מקומיות: בורשט, פלמני, אוליבייה—הן לא נמצאות ב-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
)
}
}בקשות תזונתיות מקבילות באמצעות // 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 ) } } הן קריטיות: עם 3 מנות בפריים, בקשות רציפות גורמות לשהייה של פי 3.
כיצד להעריך מנה ללא אובייקט ייחוס?
אם אין מטבע או צלחת סטנדרטית בפריים, השתמשו ב-ARKit להערכת עומק הסצנה. ב-iOS, ARSession ותמונת עומק מספיקים. מרווח השגיאה של 15–25% מקובל למעקב יומי. חלופה היא לבקש מהמשתמש לבחור סוג מיכל מתוך הגדרות קבועות מראש. עם כיול נכון, דיוק הערכת המנה נשאר מעל 70%.
מנות מורכבות: גישות לזיהוי
תמונה של בורשט מכילה סלק, כרוב, גזר, תפוחי אדמה, בשר ושמנת חמוצה בפרופורציות לא ידועות. שני פתרונות:
מאגר מתכונים. LLM או מודל מותאם מפרק את המנה למרכיבים על בסיס מתכון. עובד למנות סטנדרטיות, פחות טוב לבישול ביתי עם וריאציות.
תיקון משתמש. לאחר זיהוי אוטומטי, המשתמש רואה את ההרכב המשוער ויכול להסיר או להוסיף מרכיבים. החלקה להסרה על מרכיב, סליידר לגרמים. חוויית משתמש זו טובה מהותית מ"דיוק של 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
ארוחה שנרשמה צריכה להיכנס למערכת הבריאות. אנו פועלים לפי ההמלצות של אפל עבור 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)
}הרשאות מתבקשות מראש באמצעות TaskGroup. טעות נפוצה היא לבקש הרשאות בהשקה הראשונה של האפליקציה, לפני שהמשתמש רואה ערך. אנו ממליצים לבקש ברגע רישום הארוחה הראשונה—ההמרה עולה ב-30%.
מחסומי דיוק וכיצד להציג אותם ביושר
אפילו מודל טוב נכשל על מנות לא סטנדרטיות, תאורה לקויה וזוויות חריגות. הסתרת אי-ודאות היא טעות. הציגו ציון ביטחון לצד התוצאה.
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 (אנדרואיד) לפעולה על המכשיר. ספקו גיבוי ל-API בענן כאשר הביטחון נמוך.
- יישמו הערכת מנה. שלבו ARKit/ARCore להערכה אוטומטית או הגדרות מיכל קונטקסטואליות לקלט ידני.
- חברו מאגר נתונים תזונתי. קשרו את USDA FoodData Central למוצרים בסיסיים, השלימו עם נתונים מותאמים אישית למנות אזוריות.
- הוסיפו HealthKit/Health Connect. אוטומציה של רישום ארוחות, בקשת הרשאות ברגע הרישום הראשון.
מה כלול בעבודה
- עיצוב ארכיטקטורה ובחירת API: ניתוח קוד קיים, בחירת שירותי זיהוי ומאגרי נתונים תזונתיים אופטימליים.
- פיתוח פייפרליין: אינטגרציה של זיהוי, הערכת מנה וחיפוש נתונים—ב-iOS (Swift) ואנדרואיד (Kotlin).
- התאמת UI/UX: מסכי קלט הניתנים להתאמה אישית, עריכת הרכב, הצגת ביטחון.
- אינטגרציית HealthKit/Health Connect: רישום ארוחות אוטומטי למערכת הבריאות.
- תיעוד ותמיכה: אספקת קוד, הוראות פריסה, דוחות בדיקה.
טעויות אינטגרציה נפוצות
- בקשת הרשאות HealthKit לפני השימוש הראשון (מוריד המרה).
- חוסר טיפול בשגיאות לחוסר זמינות רשת (APIs לזיהוי).
- התעלמות מווריאציות מנות אזוריות (רק מאגרי נתונים מערביים).
- כיול ARKit שגוי להערכת מנה במכשירים שונים.
הערכות זמן
| שלב | משך |
|---|---|
| פייפרליין בסיסי + API זיהוי אחד | 1–2 שבועות |
| הוספת הערכת מנה (AR) | +1 שבוע |
| מנות מורכבות ועריכה | +1 שבוע |
| אינטגרציית HealthKit / Health Connect | +3–5 ימים |
| פונקציונליות מלאה (היסטוריה, נורמות, בדיקות) | 1–2 חודשים |
צרו קשר להערכת הפרויקט שלכם—נחשב זמנים ועלויות מדויקים. בקשו ייעוץ לדיון בפרטי האינטגרציה עם האפליקציה שלכם. חיסכון בתקציב הפיתוח מושג באמצעות שימוש במודולי פייפרליין מוכנים. הפחתת עלויות פיתוח פונקציות AI אפשרית על ידי בחירת APIs מוכנים במקום אימון מודלים מותאמים אישית.
קבלו ייעוץ—נעזור לכם לבחור את הארכיטקטורה האופטימלית לזיהוי מזון.







