An OpenCV, C++ project that generates an aesthetic "low-poly" rendition of an image using a Delaunay triangulation algorithm.
OpenCV is the premier open-source computer vision library. It abstracts and optimizes matrix operations commonly used in image processing and machine learning. For this project, the main modules (e.g. core, imgproc, imgcodecs, and highgui) should be sufficient. Find Releases here or search your favorite package manager. All this project cares about is that CMake can find_package it.
Though this is primarily a CLI tool, it features GUI interactivity, so if you want that, be sure your environment can produce GUI windows (e.g. you may need to set up something like X11 if you are in a true CLI-only environment).
This tool allows for a high degree of customizability through command-line options (shoutout to p-ranav/argparse for the excellent library). For example, it may be desirable to downscale the input for better computational performance while upscaling the output to preserve sharpness and acuity. Other options apply to specific pipeline parameters and are given reasonable defaults. A brief description of the pipeline can be found below.
lowpoly [--help] [--version]
[--output PATH]
[--preproc-scale SCALE] [--target-input-width WIDTH]
[--postproc-scale SCALE] [--target-output-width WIDTH]
[--edge-threshold THRESHOLD]
[--anms-kernel-range RANGE]
[--salt RATIO]
[--silent] [--interactive] [--all]
FILE
Positional arguments:
FILE Path to input image
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
-o, --output PATH Output image path
-s, --preproc-scale SCALE Initial preprocessing scale factor [default: 1]
-w, --target-input-width WIDTH Scale the input image to this size before processing (overrides -s)
-S, --postproc-scale SCALE Final postprocessing scale factor [default: 1]
-W, --target-output-width WIDTH Scale the output image to this size after processing (overrides -S)
-t, --edge-threshold THRESHOLD Minimum edge strength on the interval [0.0, 1.0] [default: 0.4]
-k, --anms-kernel-range RANGE Range of adaptive non-max suppression kernel radius [default: "2-7"]
-r, --salt RATIO Proportion (expressed as decimal) of random salt added [default: 0.001]
-q, --silent Suppress normal output
-i, --interactive Use GUI to preview and supply an interactive loop
-a, --all Write all intermediate outputs to files
- Read in image and apply any scaling.
- Extract edge information via Sobel filter.
- Extract vertex information from edge data via non-max suppression.
- Pass vertices to Delaunay triangulation algorithm.
- Extract triangles from generated graph.
- Determine average color in each triangle.
- Scale geometric information for output.
- Stitch together mosaic of colored triangles for final output :)
- Uses the Sobel operator.
--edge-thresholdapplies to the magnitude of difference vector at each pixel0.0⇒ flat (i.e. no edge, zero vector)1.0⇒ maximum edge (e.g. between black and white regions, max Euclidean distance between pixel vectors)
Edge data extracted via Sobel filter. Bright spots have stronger edges; dark spots are comparatively flat.
- Radius of the kernel is adaptive based on proximity to strong edges
--anms-kernel-rangeaffects the mapping from edge strength to NMS kernel size--saltaffects the amount of random noise added afterwards
Vertices extracted via adaptive non-max suppression. Random salt noise has been added as well to provide visual interest to the final output.
- What is it?
delaunaymodule implements the divide-and-conquer technique published by Guibas and Stolfi withcv::Pointas the payload data- Uses the simplified data structure designed by Ian Henry (this is an incredible read with interactive graphics!)
Delaunay triangulation of extracted vertices. Each triangle can be extracted from this graph representation through a recursive traversal.
- Traverses Delaunay graph recursively to extract triangles
- Uses
cv::meanwith a mask to average color in each region - Output can be scaled arbitrarily large (compute-bound) because extracted information is geometric before being rasterized

