Stippling is the creation of a pattern simulating varying degrees of solidity or shading by using small dots (Wikipedia).StippleGen is a piece of software that renders images using stipple patterns, which I discovered on Xi’an’s blog a couple days ago.

Stippled version of a sketch by Paul CĂ©zanne, rendered in R

StippleGen uses an algorithm by Adrian Secord (described here) that turns out to be related to a problem in spatial statistics, specifically how to mess with high-order statistics of point processes while controlling density. The algorithm is a variant of k-means and is extremely easy to implement in R.


stipple <- function(im,nPoints=1e3,gamma=2,nSteps=10)
    dens <- (1-im)^gamma
    xy <- sample(nPix(im),nPoints,replace=TRUE,prob=dens) %>% coord.index(im,.) %>% select(x,y)
    for (ind in 1:nSteps)
        xy <- cvt(xy,dens)
        plot(im); points(xy,col="red")

plot.stipple <- function(im,out,cex=.25)
    g <- imgradient(im,"xy") %>% map(~ interp(.,out))

##Compute Voronoi diagram of point set xy,
##and return center of mass of each cell (with density given by image im)
cvt <- function(xy,im)
    voronoi(xy,width(im),height(im)) %>% %>%
        mutate(vim=c(im)) %>%
        group_by(value) %>%
        dplyr::summarise(x=weighted.mean(x,w=vim),y=weighted.mean(y,w=vim)) %>%
        select(x,y) %>%
        filter(x %inr% c(1,width(im)),y %inr% c(1,height(im)))

##Compute Voronoi diagram for points xy over image of size (w,h)
##Uses a distance transform followed by watershed 
voronoi <- function(xy,w,h)
    v <- imfill(w,h)
    ind <- round(xy) %>% index.coord(v,.)
    v[ind] <- seq_along(ind)
    d <- distance_transform(v>0,1)

#image from original paper
im <- load.image("")
out <- stipple(im,1e4,nSteps=5,gamma=1.5)

TSP art is a variant where you solve a TSP problem to connect all the dots.

##im is the original image (used only for its dimensions)
##out is the output of the stipple function (dot positions)
draw.tsp <- function(im,out)
    tour <- out %>% ETSP %>% solve_TSP

##Be careful, this is memory-heavy (also, slow)
out <- stipple(im,4e3,gamma=1.5)

I’ve written a more detailed explanation on the imager website, with other variants like stippling with line segments, and a mosaic filter.