iterative image reconstruction using random cubic bézier strokes, accelerated on metal
NOTE images used here are all under open access by The Met
same input & different seeds → different reconstructions → simple animation:
cargo build -r
splined: iterative image reconstruction with random cubic bézier strokes ( metal-accelerated ) usage: splined [ args ] args: -n, --number max splines to draw ( default: ( w*h ) ^0.7 ) -b, --batch batch size per gpu step ( default: 32 ) -s, --seed rng seed ( default: 0 ) --max-gpu max gpu usage in ( 0, 1 ] ( default: 1.0 ) -l, --log <0..3> logging level ( default: 1 ) -o, --output output file or dir ( default: output.png ) -c, --current current canvas image to resume from ( single-file only ) --nth save every nth accepted stroke ( uses -o as dir ) --bg initial canvas color ( default: avg ) -a, --alpha stroke alpha in [ 0, 1 ] ( default: 1 ) --min-accept-ratio stagnant if accepted < batch*ratio ( default: 0.02 ) --max-stagnant-batches stop after this many stagnant batches ( default: 10 ) input: - file: writes one image to -o/--output ( default: output.png ) - dir: -o/--output must be a dir ; mirrors input tree under it - --nth: saves frames to output dir every nth accepted stroke ; also writes final.png examples: splined in.png -o out.png splined in.png -n 5000 -b 64 -s 42 -o out.png splined in.png --nth 50 -o frames/ splined images/ -o results/ -n 5000 -b 64 -s 42 --nth 50
convert input to oklab color space
initialize canvas to image average (or --bg )
) repeat until target stroke count or convergence: sample batch of random cubic béziers (4 control points, uniform over image) rasterize each curve to coverage mask set stroke color to coverage-weighted mean of target pixels accept curves that strictly reduce squared oklab error (Δε² < 0) commit accepted strokes to canvas
export final canvas
Geometrize: a desktop app that geometrizes images into geometric primitives