Modern GPUs can draw billions of triangles per second. That’s great for 3D artists and because they don’t have to work nearly as hard to optimize their assets.

But there’s a distinct charm in the aesthetics born from simplicity.

Keeping an image readable and recognizable while stripping away detail is a fun challenge. Done well, the results are often striking:

A few years ago I wrote a script that stylizes any image as low-poly. Here’s a few samples processed through that script:

The first version of this generator (Kon) was Python-based, using numpy, opencv, and scipy. It got the job done, but it was slow - about 15 seconds per image.

I figured I could do better, so I revisited the generator to do a Rust rewrite.

How it works

I’ll start with this beetle I photographed at MacRitchie reservoir:

Step 1: Smart Point Sampling

The key to a good low-poly image is choosing the right points. Instead of random sampling, Kon uses a Sobel filter to focus on edges and important features.

The Sobel gradient of an image highlights changes in intensity - it’s bright where there’s high-frequency detail and dark where the intensity doesn’t change much. Essentially, it acts like an edge detector.

To further emphasize the most salient edges, I also raise the contrast on the Sobel gradient by exponentiating it:

We then run weighted random sampling over the gradient image to pick a set of points to act as the basis for our low-poly image’s polygons:

Step 2: Delaunay Triangulation

Once the points are picked, they’re connected with Delaunay triangulation, which ensures well-formed triangles without overlap.

  • Built with the spade crate for efficient triangulation.
  • Edge handling to prevent artifacts or gaps.
  • Parallelized with Rayon for speed.

Step 3: Coloring the Polygons

Each triangle’s color is determined using:

  • K-Means clustering for dominant colors.
  • Median Cut for color quantization.
  • Mean color fallback for tiny triangles.

To make sure everything worked, I generated debug images at different stages. This made it easy to spot issues like uneven point distribution and triangulation artifacts.

What’s Next?

Kon is a lot faster now, but there’s still a lot missing and many ways to improve it. Here’s a few things I’ve been thinking about:

  • Manual Point Placement – Let users tweak key points.
  • WASM GUI – A browser-based interactive tool.
  • More Polygon Types – Triangles are great, but what about hexagons? And other shapes?
  • Selective Effects – Low-poly only on certain parts of an image.
  • GPU Acceleration – CUDA or Vulkan for real-time processing.
  • Low-Poly Video – Extending the approach to moving frames.

Inspiration

When I revisited this project, I found other great takes on low-poly generation:

If you want to try the generator, check out the GitHub repo