A Web-based Implementation of Weighted Voronoi Stippling

— a DH2323 project

Author: Haohao Yu (haohao@kth.se)

00. Proposal and Literature Research

Pointillism Stippling

In the beginning, when I found Daniel Shiffman's new coding challenge about stippling, I thought of Pointillism, a painting technique pioneered by French artist Georges Seurat during the Post-Impressionist period. Therefore, my initial project proposal was to extend the stippling project into a Pointillism filter app—just applying the color method Seurat used in his works. However, after a deeper dive into some papers about digital Pointillism, I realized that stippling and Pointillism are totally different painting methods, and therefore the digital methods to generate them with a computer are also totally different. The methods computer scientists use to generate Pointillism-style images are too complex for me and for this course project, so I decided to focus only on stippling.

01. Build the Web App Framework and First Try with Delaunator

Delaunay Triangulation

Initially, I wanted to create my project as a single-page web app that allows users to upload images and get filtered stippling images with a control panel to adjust some parameters. I quickly made this with Next.js. For manipulating pixels, I chose p5.js, which I'm familiar with and is popular in the web development field. For calculating Delaunay triangles based on a group of points, I chose Mapbox's Delaunator because it performs the fastest in comparison.

The first step was to generate a group of random points from the input image by setting a brightness threshold for each pixel. Then, I used the Delaunator library's function to easily get the Delaunay triangles.

result was quite good, and it really ran fast as expected!

02. Calculate Voronoi Diagram Based on Delaunay Triangles

Voronoi Diagram

Compared with d3-delaunay, which was used by Daniel Shiffman in his project, Mapbox's Delaunator is a relatively low-level library without an API to generate Voronoi diagrams directly. Therefore, I decided to code the algorithm myself.

The Vertices of Voronoi polygons are just the circumcenters of Delaunay triangles. Using the formula on this website: [Circumcenter of a Triangle](https://byjus.com/maths/circumcenter-of-a-triangle/), I completed the calculateVoronoi function.

The result was good as follows.

03. Optimize Points Distribution with Lloyd's Algorithm

The most important part of the paper Weighted Voronoi Stippling is about Lloyd's algorithm. The basic idea is to calculate the centroids of each Voronoi cell or polygon and move the corresponding point to its location, then generate a new Voronoi diagram and repeat this process until a stable point distribution is achieved, resulting in the final stippling image.

To implement this in code, I got help from Paul Bourke's website on how to calculate the centroid coordinate of a polygon.

Centroid Formula

To calculate the weights of each pixel based on its brightness, I referred to W3C's definition of Relative Luminance: "For the sRGB color space, the relative luminance of a color is defined as L = 0.2126 * R + 0.7152 * G + 0.0722 * B".

With the knowledge above, I finished the updatePoints function. The final program could run, but it ran very slowly, which I thought might be related to some performance or compatibility issues with p5.js. It might only perform better on its official web editor. So, I migrated my algorithm to a p5.js web editor sketch. The final result was relatively satisfactory.

Stippling example with low-contrast portrait

The face part of this portrait is not good, which I think is because of insufficient grayscale contrast. An image with stronger grayscale contrast may perform better.

Original image with strong grayscale contrast

Yes it is! Bye! :)