Weighted Voronoi Stippling

May 13, 2026 · View on GitHub

High-performance implementation of the Weighted Voronoi Stippling algorithm for converting images into artistic stipple representations. Uses Numba JIT compilation for 5-15x speedup on multi-core CPUs.

Example Output

OriginalStipplesTour Visualization
OriginalStipplesTour

Quick Start

  1. Install dependencies:

    pip install -r requirements.txt
    
  2. Generate stipples:

    python stippling.py images/example-1024px.png --stipples 10000
    
  3. Visualize points:

    python visualize.py stipplings/tsp/example-1024px_10000.tsp --points-only
    

Usage

Basic Stippling

Generate stipples from any image:

# Default settings (5000 stipples, 30 iterations)
python stippling.py images/photo.jpg

# Custom settings
python stippling.py images/photo.jpg --stipples 10000 --iter 50 --radius 2.0

Output files:

  • stipplings/png/photo_5000.png - Visual stipple image
  • stipplings/tsp/photo_5000.tsp - Coordinate data for TSP solvers

Visualization

Points only:

python visualize.py stipplings/tsp/photo_5000.tsp --points-only

Tour lines (supports TSPLIB TOUR, Concorde .sol, and linkern output):

python visualize.py stipplings/tsp/photo_5000.tsp --tour-path path/to/photo.tour
python visualize.py stipplings/tsp/photo_5000.tsp --tour-path photo_5000.sol
python visualize.py stipplings/tsp/photo_5000.tsp --tour-path photo_5000.opt.tour
python visualize.py stipplings/tsp/photo_5000.tsp --tour-path photo_5000.heu.tour

Accepted tour formats:

  • TSPLIB TOUR files (.tour, .opt.tour, .heu.tour)
  • Concorde integer-sequence outputs (.sol and similar)
  • Concorde linkern tour output

--tour-format defaults to auto, so you usually only need --tour-path. Use --tour-format and --tour-index-base only for troubleshooting format/base detection.

TSP Solver Workflows

To create continuous line drawings, solve the TSP using external solvers:

linkern (fast heuristic):

linkern -o visualizations/tour/photo_5000.heu.tour stipplings/tsp/photo_5000.tsp
python visualize.py stipplings/tsp/photo_5000.tsp --tour-path visualizations/tour/photo_5000.heu.tour --output visualizations/png/photo_5000_linkern.png

Concorde (default .sol output):

concorde stipplings/tsp/photo_5000.tsp
python visualize.py stipplings/tsp/photo_5000.tsp --tour-path photo_5000.sol --output visualizations/png/photo_5000_concorde.png

Concorde (explicit TSPLIB TOUR output with -o):

concorde -o visualizations/tour/photo_5000.opt.tour stipplings/tsp/photo_5000.tsp
python visualize.py stipplings/tsp/photo_5000.tsp --tour-path visualizations/tour/photo_5000.opt.tour --output visualizations/png/photo_5000_concorde.png

LKH (parameter-file based):

  • LKH usually runs from a parameter file instead of direct CLI flags.
  • Include PROBLEM_FILE = stipplings/tsp/photo_5000.tsp.
  • Include a tour-output setting such as TOUR_FILE = ... or OUTPUT_TOUR_FILE = ... depending on your LKH version/configuration.
  • Then visualize the produced tour file:
python visualize.py stipplings/tsp/photo_5000.tsp --tour-path path/to/lkh-output.tour

Custom LK solver output:

  • Custom LK outputs .heu.tour in TSPLIB TOUR format.
python visualize.py stipplings/tsp/photo_5000.tsp --tour-path path/to/photo_5000.heu.tour --output visualizations/png/photo_5000_custom_lk.png

Option 3: Online solvers Upload your .tsp file to NEOS Server for optimal solutions.

Command Reference

stippling.py

OptionDefaultDescription
--stipples5000Number of stipples (1-1,000,000)
--iter30Lloyd relaxation iterations (1-1000)
--radius1.0Stipple radius in pixels (0.1-100)
--no-numba-Disable JIT compilation
--verbose-Detailed progress logging

visualize.py

OptionDescription
--points-onlyShow only stipple points
--lines-onlyShow only tour lines
--tour-pathPath to TSPLIB TOUR/.sol/linkern tour file
--tour-formatauto, tsplib, concorde-sol, linkern
--tour-index-baseConcorde index base: auto, 0, 1
--outputSave to file instead of display
--point-sizePoint size (default: 1.0)
--line-widthLine width (default: 2.0)

File Organization

weighted-voronoi-stippling/
├── images/              # Input images (tracked by git)
├── stipplings/
│   ├── png/            # Generated stipple images
│   └── tsp/            # TSP coordinate files
├── visualizations/
│   ├── tour/           # TSP solution files (.tour)
│   └── png/            # Tour visualization images
├── stippling.py         # Main stippling algorithm
└── visualize.py         # Visualization tool

Files are automatically named with stipple counts: example_5000.png, example_5000.tsp, etc.

Technical Details

  • Algorithm: Weighted Voronoi stippling with Lloyd relaxation
  • Performance: 5-15x speedup with Numba JIT compilation
  • TSP Format: Standard TSPLIB format for compatibility with solvers
  • Fallback: Pure Python mode when Numba unavailable

References