Image Pre-processing

This section helps ensure that your input images are optimized for LogMeal’s recognition models, improving both accuracy and reliability while staying within API limits.

Before sending food images to the LogMeal API, it’s important to follow a few best practices to ensure the best recognition accuracy. Proper pre-processing reduces errors, speeds up processing, and improves the quality of the results.


Why Pre-processing Matters

The API relies on computer vision models trained on millions of images. Clear, well-structured input images lead to:

  • More accurate dish recognition
  • Better nutritional information extraction
  • Faster response times

General Guidelines

  • Lighting: Ensure good, natural lighting. Avoid shadows covering the food.
  • Focus: Images should be sharp and not blurry.
  • Framing: The food should take up most of the image area.
  • Multiple Dishes: If multiple dishes are present, ensure each one is clearly visible.
  • Convert to JPG: Always convert your images to .jpg format. JPG is the standard input format for the LogMeal API. It ensures:
    • Wide compatibility across platforms and tools.
    • Consistent decoding on the server side.
    • Optimized compression for photographic content (like food).
  • Reduce File Size (under 1 MB): Images must be smaller than 1MB to:
    • Ensure faster uploads and lower latency.
    • Prevent timeouts in API requests.
    • Reduce bandwidth consumption when sending many images.
    • Stay within LogMeal API’s upload size limitations.
  • Avoid clutter: Background objects (cutlery, menus, etc.) may confuse the model.

Depth & Sequence Capture

Some advanced use cases (like Food Quantity Detection or Food Waste Detection) benefit from extra capture modes:

  • 📏 Depth images – If your device supports depth sensors, provide paired RGB + depth images for better quantity estimation.
  • 🎞️ Sequence capture – For leftovers/waste detection, send before & after meal images.

👉 For details on supported endpoints in your Plan, see Plan Subscription Details.

See details on how to implement this data capture method on the Food Quantity Detection use case.


Sample Images

  • Good capture:
    • Bright, centered dish on a plate
    • Minimal background noise
  • Poor capture:
    • Dark image with shadows
    • Dish partly cropped
    • Multiple overlapping plates
    • Blurry image

Code Examples

The following snippets mirror the official examples in the OpenAPI/Swagger file to ensure consistent behavior, including EXIF orientation preservation and iterative downscaling below 1MB.

Convert to JPG while preserving EXIF orientation (Python)

import os
from PIL import Image
import piexif

# Path of the original image (e.g., PNG/HEIC/JPEG)
path_original_image = '<path-of-the-original-image>'
global_path = '<output-folder-path-ending-with-/> '

# Open and convert to RGB
im = Image.open(path_original_image)

# [IMPORTANT to keep image orientation]
exif_dict = piexif.load(im.info.get('exif', b''))
exif_bytes = piexif.dump(exif_dict)
rgb_im = im.convert('RGB')

# Derive output name and write JPG
image_name = os.path.basename(path_original_image)
image_name_noext = os.path.splitext(image_name)[0]
path_jpg = os.path.join(global_path, image_name_noext + '.jpg')

rgb_im.save(path_jpg, 'JPEG', exif=exif_bytes, quality=90)
print('Saved:', path_jpg)

Reduce image file size to < 1MB (Python)

import os
from PIL import Image
import piexif

path = '<path-to-jpg>'  # e.g., the output from the conversion step

im = Image.open(path)
exif_dict = piexif.load(im.info.get('exif', b''))
exif_bytes = piexif.dump(exif_dict)
rgb_im = im.convert('RGB')

# Helper to get size in MB
size_mb = lambda p: os.path.getsize(p) >> 20  # integer MB using bit shift

# Current dimensions
width, height = rgb_im.size

# Iteratively reduce size until < 1MB
while size_mb(path) >= 1:
    # Resize image to 75% of current size
    width, height = int(width * 0.75), int(height * 0.75)
    rez_image = rgb_im.resize((width, height), Image.ANTIALIAS)

    # Save keeping EXIF
    rez_image.save(path, 'JPEG', exif=exif_bytes, optimize=True, quality=85)

print('Final size (MB):', size_mb(path))

Why this approach?

  • Preserves EXIF orientation so dishes aren’t rotated incorrectly.
  • Uses a progressive, quality-preserving downscale loop to reliably stay under 1MB.
  • Matches the server’s expectations, avoiding 413 Request Entity Too Large and keeping inference latency low.

Next Steps