DEV Community

wellallyTech
wellallyTech

Posted on

Stop Guessing Calories: Building a 3D Food Volume Estimator with SAM and GPT-4o πŸ₯‘πŸ”₯

Let's be honest: manual calorie tracking is a nightmare. Most apps ask you to log "one medium apple," but what does "medium" even mean in a world of giant Honeycrisps? Traditional Computer Vision approaches often fail because they lack depth perception, treating a flat photo like a 2D sticker.

In this tutorial, we are going to bridge the gap between pixels and nutrition. We’ll combine Meta’s Segment Anything Model (SAM) for pixel-perfect object isolation, OpenCV for 3D volume estimation, and GPT-4o Multimodal AI for intelligent nutritional density reasoning. This isn't just "identifying" a burger; it's measuring it.

By the end of this guide, you'll understand how to implement 3D reconstruction logic and leverage high-level reasoning to turn a single smartphone photo into a detailed nutritional report.


πŸ— The Architecture: From Pixels to Volumetric Data

Before we dive into the code, let’s look at the data pipeline. We aren't just running a classifier; we are building a multi-stage vision pipeline.

graph TD
    A[Raw Food Image] --> B{SAM Segmentation}
    B -->|Masks| C[OpenCV Contour Analysis]
    B -->|Cropped Image| D[GPT-4o Vision Input]
    C --> E[Depth & Volume Estimation]
    E --> F[Prompt Engineering]
    D --> F
    F --> G[GPT-4o Reasoning]
    G --> H[Final Calorie & Macro Report]
Enter fullscreen mode Exit fullscreen mode

πŸ›  Prerequisites

To follow along, you'll need an Intermediate-to-Advanced grasp of Python and the following stack:

  • PyTorch: To run the SAM encoder/decoder.
  • Segment Anything (SAM): Specifically the vit_h or vit_l weights.
  • OpenCV: For geometric calculations.
  • OpenAI API: For the GPT-4o multimodal magic.

πŸš€ Step 1: Pixel-Perfect Segmentation with SAM

First, we need to tell the computer exactly where the food ends and the plate begins. Traditional bounding boxes are too "noisy." We need masks.

import torch
import cv2
import numpy as np
from segment_anything import sam_model_registry, SamPredictor

# Load the heavy hitter: SAM
device = "cuda" if torch.cuda.is_available() else "cpu"
sam = sam_model_registry["vit_h"](checkpoint="sam_vit_h_4b8939.pth").to(device)
predictor = SamPredictor(sam)

def get_food_mask(image, input_point):
    predictor.set_image(image)
    masks, scores, _ = predictor.predict(
        point_coords=np.array([input_point]),
        point_labels=np.array([1]), # Positive prompt
        multimask_output=True,
    )
    # Pick the mask with the highest confidence score
    return masks[np.argmax(scores)]
Enter fullscreen mode Exit fullscreen mode

πŸ“ Step 2: Estimating Volume (The 3D "Hack")

Without a LiDAR sensor, calculating volume from a single 2D image is mathematically "undetermined." However, we can use Reference Object Scaling (e.g., using the plate size or a coin) and an Ellipsoid Approximation.

def estimate_volume(mask, reference_scale=0.05):
    """
    Simplistic volume estimation: V = 2/3 * Area * Height-approximation
    reference_scale: pixels to cm conversion
    """
    contours, _ = cv2.findContours(mask.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnt = max(contours, key=cv2.contourArea)

    # Calculate area in cm^2
    area_px = cv2.contourArea(cnt)
    area_cm2 = area_px * (reference_scale ** 2)

    # Assume height is roughly proportional to the minor axis of the food
    _, (w, h), _ = cv2.minAreaRect(cnt)
    estimated_height_cm = min(w, h) * reference_scale * 0.7 

    volume_cm3 = area_cm2 * estimated_height_cm
    return volume_cm3
Enter fullscreen mode Exit fullscreen mode

🧠 Step 3: GPT-4o Multimodal Reasoning

Now we have the Volume (cmΒ³) and the Visual Features. We send both to GPT-4o. Why? Because GPT-4o knows the difference in density between a 100cmΒ³ bowl of salad and a 100cmΒ³ block of cheddar cheese.

import openai

client = openai.OpenAI(api_key="YOUR_SK")

def get_nutritional_analysis(image_path, volume_cm3):
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": f"The food in this image has an estimated volume of {volume_cm3:.2f} cm3. Identify the food and calculate total calories, protein, and fats based on this specific volume."},
                    {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{encode_image(image_path)}"}}
                ],
            }
        ],
    )
    return response.choices[0].message.content
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ The "Official" Way to Scale

While this DIY pipeline works for a prototype, production-grade Vision AI requires robust handling of edge cases (like overlapping food or low-light conditions).

For more production-ready examples and advanced patterns regarding Vision-Language Models (VLM) and high-throughput AI architectures, I highly recommend checking out the engineering deep dives at wellally.tech/blog. They cover the nuances of deploying SAM in low-latency environments that we couldn't fit into this single post! πŸ₯‘πŸ“ˆ


🏁 Conclusion

By combining the spatial precision of SAM with the semantic intelligence of GPT-4o, we’ve moved from "guessing" to "measuring." This hybrid approach is the future of HealthTech and AI-driven lifestyle apps.

What’s next?

  1. Try adding a Depth Map model like MiDaS to the pipeline for even more accurate height estimation.
  2. Experiment with few-shot prompting to give GPT-4o specific regional food datasets.

Did this save you from a calorie-counting headache? Drop a comment below or πŸ¦„ if you're going to build this!

Top comments (0)