Skip to content

KullGames . ImageTool . Milestone 4.1

Turn a flat photo into a spinning 3D model.

Click one pixel of a subject. The tool magic-wand seeds it, runs GrabCut to prop the whole object off its background, inflates that flat silhouette into a rounded, watertight solid with the classic Teddy method, orbits a camera around it to bake a turntable GIF, and exports the mesh as STL + OBJ/MTL/PNG. No neural net, no depth sensor, no multi-view rig - just classical geometry, written entirely in C# against nothing outside the .NET base class library.

Magic-wand + GrabCut Teddy inflation Software rasterizer STL / OBJ export Zero dependencies

Everything below is a fresh render from this run. The 39-photo unattended batch swept the whole folder in 120.2 s (3.1 s/image, single-threaded): 30 graded a compact OBJECT, 2 partial, 7 honest scenes - every GIF round-trip verified, every mesh exported to STL and OBJ.

A campfire flame, cut out of a photo and inflated into a puffed 3D solid, rotating on a turntable.

The pipeline, on screen

Watch a photo become a solid.

Each stage of the pipeline emits a real image, so the whole path is legible - not a black box. Left to right: the selection, the cut, and the spin.

For each photo: the input frame, then the magic-wand selection outlined in place, then the RGBA cutout composited on a checkerboard.
Step 1 - select: the magic wand
A CIELAB tolerance flood grows from one click. Per photo this loops input photo -> selection outlined in place -> the isolated RGBA cutout on a checkerboard, so you can see exactly what got grabbed.
A side-by-side GIF. Left: the single-seed Tier-1 flood fill grabbing only a sliver. Right: GrabCut recovering the whole multi-colour subject, with the seed rectangle drawn.
Step 2 - cut: GrabCut beats the single-seed flood
LEFT = the Tier-1 wand (one seed colour), RIGHT = GrabCut (models the whole foreground and background colour distributions, cuts on a min-cut). On the campfire the wand grabs 2.5% (a sliver of the white-hot core); GrabCut recovers the whole 11.1% flame.
A campfire flame isolated on a transparent background - the GrabCut cutout that feeds the inflator.
The cutout that feeds the inflator
GrabCut's RGBA foreground - the exact bitmap the Teddy step domes into a mesh, and the same pixels painted onto the 3D form as per-vertex colour.
A synthetic multi-colour disc inflated into a plump biconvex lens, rotating.
Step 3 - inflate + spin: a textbook dome
A clean synthetic cutout inflates to a biconvex lens - the Teddy step isolated from any segmentation noise. 6,300 tris, watertight (0.00% boundary edges), 24-frame turntable.
WATERTIGHT 6,300 tris synthetic

Batch, unattended

Thirty-nine photos, zero clicks.

Point model3d-batch at a folder and it auto-seeds each photo with a border-prior saliency cue, runs the same GrabCut -> Inflate -> Turntable pipeline, and exports a mesh per image. Then it bakes two "see everything at once" artifacts and prints an honest per-image verdict table.

A 7-by-6 contact sheet of all 39 inflated subjects, each tile tagged OBJECT, PARTIAL, or SCENE in green, amber, or grey.
All 39 subjects, one glance
One angled turntable frame per photo, each tile tagged with its name and colour-coded verdict, exactly as the batch driver bakes it. The final tally: 30 OBJECT, 2 PARTIAL, 7 SCENE.
30 OBJECT2 PARTIAL7 SCENE
A concatenated rotation tour of the strongest subjects, spun one after another.
Rotation tour
The strongest subjects (objects first) spun back to back - capped at 20 to keep the GIF small, with the dropped names logged, never silently truncated.

Exports

Every mesh is a real, printable file.

The turntable is only the preview. Each inflated solid is written as binary STL and as OBJ + MTL + texture PNG - watertight, per-vertex coloured, and openable in any slicer (Cura, PrusaSlicer, Bambu) or mesh viewer (MeshLab, Blender, Windows 3D Viewer). Download the actual files this run produced:

Binary STL has no magic number, so a file sniffer reports "data" - that is expected; the byte size is exactly 84 + triangles . 50. Keep the OBJ, MTL, and texture PNG together in one folder so the photo maps on via the MTL's map_Kd.

Also in the box

Straight lines and geometric shape.

The same classical toolkit powers a recognition layer: a from-scratch Hough transform finds straight lines over Canny edges, and a shape descriptor (convex hull, rotating calipers, PCA axis) sorts a mask into TallThin / Wide / Round / Irregular. It reports geometry, not identity - it says "tall and thin", never "a person".

Per photo: an input frame, a Hough frame with detected cyan lines and an angle label, and a shape frame with the cutout outline and a magenta PCA axis plus a geometric-class label.
Hough lines + geometric class
Per photo: INPUT, then a HOUGH panel (Canny + Sobel edges + detected straight lines with their angle), then a SHAPE panel (cutout outline + magenta PCA principal axis + the geometric class). The self-test recovers known 0/45/90-degree lines to within 0.0 degrees.

How it works

Four classical steps, no learned model.

Select. A click seeds a CIELAB magic-wand flood; its bounding box seeds GrabCut, which models the whole foreground and background colour distributions as Gaussian mixtures and cuts the boundary with a min-cut over the pixel grid.
Height field. A two-pass chamfer distance transform of the mask gives each pixel its distance to the nearest edge - high in the middle of a wide region, low along a thin sliver.
Inflate. Dome it with h = Thickness . s . sqrt(dt . Dmax) - the square root gives a sphere-like profile, so wide areas bulge tall and thin areas stay flat. Grid-mesh the front and back, then stitch a side wall into one closed, watertight solid.
Render + export. A Pineda software rasterizer orbits a turntable camera, shading per-vertex photo colour under a directional light, tonemaps Reinhard + sRGB, and bakes the frames into a GIF89a - then writes the mesh as STL and OBJ/MTL/PNG, all with the library's own codecs.

Honest scope

A relief, not a reconstruction.

This is a single-image inflation: the back is a mirror of the front and the sides the camera never saw are smoothly invented. It is convincing head-on and in a gentle spin, not a metrologically correct model - the honest nature of any single-snapshot method that does not hallucinate hidden geometry. Quality rides entirely on the cutout: a clean mask gives a clean solid, a landscape with no subject gives an abstract colour relief - and the batch grader says which is which, out loud, on every tile.

The technique is Teddy (Igarashi, Matsuoka & Tanaka, SIGGRAPH 1999); the segmenter is GrabCut (Rother, Kolmogorov & Blake, SIGGRAPH 2004). Both are reimplemented from scratch in pure C# over the OnlyCSharp library, against nothing outside the .NET base class library.