Cal AI, MyFitnessPal, Lose It!: four photo calorie apps looked at 102 meals. All four came in low.
If you are building anything that turns a photo of food into a number, this one is worth a minute. Researchers in the intramural program of the US National Institute of Diabetes and Digestive and Kidney Diseases (NIH) cooked 102 meals in a metabolic kitchen, where the content of every plate is know

If you are building anything that turns a photo of food into a number, this one is worth a minute.
Researchers in the intramural program of the US National Institute of Diabetes and Digestive and Kidney Diseases (NIH) cooked 102 meals in a metabolic kitchen, where the content of every plate is known. They analysed photos of each meal with the photo features of four apps and compared every estimate with the known value.
Every app came in low. Mean energy underestimate per meal:
That is roughly a third of the meal missing. All four also underestimated fat, by about 30 g; Lose It! and Cal AI underestimated carbohydrate too, by about 14 g.
Thirty grams of fat is about 270 kcal on its own (9 kcal per gram, the standard Atwater factor). That is close to the whole gap. Our reading, not the study's: fat is the part of a plate a camera sees worst — oil in the pan, butter melted into the rice, the dressing under the leaves. A vision model can name the salad and still miss the tablespoon of oil.
You can see how much of a food's energy sits in fat with any open nutrient table. Here is one, the FatTonic Food Index, where every row points at the USDA record it was read from:
import csv, io, urllib. request url = " https://fattonic.com/data/export/foods.csv " foods = list ( csv. DictReader ( io. TextIOWrapper ( urllib. request. urlopen ( url ), " utf-8 " ))) def kcal ( f ): # Atwater factors: 4 kcal/g carbohydrate and protein, 9 kcal/g fat return 4 * float ( f [ " carbs_g " ]) + 4 * float ( f [ " protein_g " ]) + 9 * float ( f [ " fat_g " ]) for f in sorted ( foods, key = lambda f: 9 * float ( f [ " fat_g " ]) / max ( kcal ( f ), 1 ), reverse = True )[: 5 ]: share = 9 * float ( f [ " fat_g " ]) / kcal ( f ) print ( f ' { f [ " name " ]: < 22 } { f [ " serving " ]: < 18 } { share: 4.0 % } of energy from fat { f [ " source_url " ] } ' ) Enter fullscreen mode Exit fullscreen mode Run today it prints pecans (87 %), walnuts (84 %), hazelnuts (81 %), avocado (75 %) and cheddar (73 %), each with its USDA FoodData Central link.
A handful of nuts on a photo is a small object carrying most of its energy as fat, which is where a size guess would hurt most.
It was presented at the American Society for Nutrition's NUTRITION meeting as a conference abstract, not a peer-reviewed paper, and the report calls the results preliminary until the full study is reviewed. It measured accuracy, not whether using an app changes anyone's health. The lead researcher's advice for a photo logged without checking portions: take the result "with a grain of salt".
FatTonic's camera does not estimate a mixed plate. It names one fresh food at a time, you tap the match, and the number comes from that food's sourced row. It is a narrower feature. This study is a good argument for keeping it narrow.
Source: Healio, Emma Bascom, "AI photo-based calorie-tracking tools underestimate them by 33%", 4 August 2026. Information, not medical advice.