simple_image_ai

AI Helpers for simple_image: Person Cutout in Pure Eiffel

v0.1.0 MIT

Overview

simple_image_ai holds the AI helpers for simple_image, running ONNX models through simple_onnx. It is pure Eiffel: no Python at run time.

Its first helper is a person cutout: a mask of the people in a photo, from u2net_human_seg, the model rembg uses.

Part of the Simple Eiffel ecosystem.

Quick Start

Installation

  1. Set the environment variable:
    export SIMPLE_EIFFEL=/d/prod
  2. Add to your ECF file:
    <library name="simple_image_ai" location="$SIMPLE_EIFFEL/simple_image_ai/simple_image_ai.ecf"/>

Cut Out a Person and Add a Glow

local
    ai: SIMPLE_IMAGE_AI
do
    create ai.make
    cutout := ai.new_cutout (ai.rembg_model_path)     -- loads in about 2 seconds; keep it
    if cutout.is_ready and then attached cutout.cut_out (photo) as al_person then
        glow := al_person.alpha
        glow.grow (6)
        glow.blur (10)
        canvas.fill_through (glow, 0xFFFFD34D, 0, 0)
        canvas.place (al_person, 0, 0)
    else
        print (cutout.last_error)
    end
end

The model file is expected at %USERPROFILE%\.rembg\models\u2net_human_seg\u2net_human_seg.onnx, where rembg keeps it. The ONNX Runtime DLL must be on the PATH.

Key Features

Person Mask

mask_for gives an IMG_MASK of the people in a photo, the same size as the photo.

Person Cutout

cut_out gives a copy with the background transparent: largest piece kept, color under alpha 0 kept.

rembg's Recipe

Lanczos to 320x320, divide by the largest value, mean and standard deviation per channel, channels first.

Pure Eiffel

simple_onnx runs the model; no Python at run time.

Fast

About 260 milliseconds per 1920x1080 frame on the CPU, against 2-3 seconds through Python.

Error Reporting

A missing or unloadable model is reported through last_error; check is_ready.

API Reference

SIMPLE_IMAGE_AI (Facade)

AI helpers for simple_image, on simple_onnx.

Initialization

make

Ready.

Helpers

new_cutout (a_model_path: READABLE_STRING_GENERAL): IMG_CUTOUT

A person cutout running the u2net_human_seg model at the path (check is_ready; loading takes about 2 seconds, so keep it).

Model files

rembg_model_path: STRING_32

Where rembg keeps u2net_human_seg: %USERPROFILE%\.rembg\models\u2net_human_seg\u2net_human_seg.onnx.

version: STRING

IMG_CUTOUT

Person cutout: a mask of the people in a photo, from the u2net_human_seg model on simple_onnx (the model rembg uses).

Initialization

make (a_model_path: READABLE_STRING_GENERAL)

Load the model at the path (about 2 seconds; do it once).

Access

mask_for (a_image: IMG_IMAGE): detachable IMG_MASK

Coverage of the people in the image (same size; 255 = person), or Void (see last_error). Alpha in the image is ignored, as rembg ignores it.

cut_out (a_image: IMG_IMAGE): detachable IMG_IMAGE

A copy of the image with the people kept and the rest transparent (largest piece only), or Void (see last_error).

Status

is_ready: BOOLEAN

Was the model loaded?

last_error: STRING

Why the model did not load or the last run failed (empty when all is well).

Constants

Side: INTEGER

The model's square input size (320).

Measured Against rembg

On a 1920x1080 video frame, the Eiffel mask was compared with rembg's own mask of the same frame (measured 2026-10-11):

MeasureResult
Intersection over union at 1280.9997
Mean difference0.09 levels
Largest difference8 levels (edge pixels, from resize rounding)
Time per frame, Eiffel on the CPUabout 260 milliseconds
Time per frame, through Python2-3 seconds
Model run against Pythonmatches to 5.4e-7 (debate 01 in simple_image's .eiffel-workflow)

Testing

/d/prod/ec.sh test -config simple_image_ai.ecf -target simple_image_ai_tests
PATH="/d/prod/simple_onnx/lib/onnxruntime/lib:/d/prod/simple_cairo:$PATH" ./EIFGENs/simple_image_ai_tests/F_code/simple_image_ai.exe

The photo tests need a photo of a person at data/input/person.png and rembg's mask of it at data/expected/person_mask_rembg.png, made by .eiffel-workflow/evidence/rembg_reference.py (an evidence tool, not product code). Test photos are never committed; without them those tests print SKIPPED.

Dependencies