Sunday, May 6, 2012

R Implementation of Six-Sided Dice Art

R Implementation of Six-Sided Dice Art

During my daily internet browsing I stumbled across a blog where people were talking about using a fairly elaborate Photoshop process to make art out of six-sided playing dice. I decided to see if I could completely automate a similar process using a R implementation with ggplot2. 

My basic approach was to load in an image file and convert it to a matrix. From there is was transformed into a data structure with Cartesian coordinates and colour values. Once I converted the photograph into this data structure I scaled the color values from one to six, with one being the lightest pixels all the way up to six being the darker pixels. Then I simply replaced each pixel with the appropriate dice depending on how light the pixel was. It's a little more complicated than that, but that's essentially how the process works. 

The function will work on any JPEG image and now it only takes a few seconds to convert any image I want into a dice image. It works best for images that are roughly 100x100 pixels and have lots of contrast; if everything is uniform than it typically doesn't render as well. The plots are much more impressive at full resolution. If Imgur ever decides to stop going over capacity I'll try to upload some full resolution plots there.  And I'm a stats guy, not comp sci, so I apologize for the shoddy code (posted on the bottom of the page), but it does get the job done. I might go back and try to tighten things up, and maybe even add the option of using black dice rather than white. 






























# May 06, 2012
# Dice Image Maker Ver 1.0

library(sp)
library(rgdal)
library(raster)
library(ggplot2)
library(plyr)
library(reshape)
library(RColorBrewer)

# Creating and Cleaning Photo Matrix

photo_temp <- raster("jeff.jpg")
p <- as.data.frame(rasterToPoints(photo_temp))
photo_temp <- as.matrix(photo_temp)
colnames(p) = c("x", "y", "value")

p$value <- cut(p$value, breaks = 6)
p$x <- p$x - .5
p$y <- p$y - .5
levels(p$value) <- c(6,5,4,3,2,1)

# Creating grid for dice photo
df <- as.data.frame(matrix(ncol = 2, nrow = nrow(photo_temp)*ncol(photo_temp)))
colnames(df) = c("x", "y")
df$x <- seq(0:(ncol(photo_temp)-1))
df$x <- sort(df$x)
df$y <- seq(0:(nrow(photo_temp)-1))
df$x <- df$x - 0.05
df$y <- df$y + 0.025

# Creating lots of dice
df2 <- as.data.frame(matrix(ncol = 2, nrow = sum(as.numeric(levels(p$value))[p$value])))
colnames(df2) = c("x", "y")


cnt <- 0
for (i in seq(1:length(p[,1]))) {

  if (p$value[i] == 6) {
  df2$x[cnt+1] <- .25 + .5 + p$x[i]
  df2$x[cnt+2] <- .25 + .5 + p$x[i]
  df2$x[cnt+3] <- .25 + .5 + p$x[i]
  df2$x[cnt+4] <- .75 + .5 + p$x[i]
  df2$x[cnt+5] <- .75 + .5 + p$x[i]
  df2$x[cnt+6] <- .75 + .5 + p$x[i]

  df2$y[cnt+1] <- .25 + .5 + p$y[i]
  df2$y[cnt+2] <- .5  + .5 + p$y[i]
  df2$y[cnt+3] <- .75 + .5 + p$y[i]
  df2$y[cnt+4] <- .25 + .5 + p$y[i]
  df2$y[cnt+5] <- .5  + .5 + p$y[i]
  df2$y[cnt+6] <- .75 + .5 + p$y[i]
  cnt <- cnt + 6
  }

  if (p$value[i] == 5) {
  df2$x[cnt+1] <- .25 + .5 + p$x[i]
  df2$x[cnt+2] <- .25 + .5 + p$x[i]
  df2$x[cnt+3] <- .5  + .5 + p$x[i]
  df2$x[cnt+4] <- .75 + .5 + p$x[i]
  df2$x[cnt+5] <- .75 + .5 + p$x[i]

  df2$y[cnt+1] <- .25 + .5 + p$y[i]
  df2$y[cnt+2] <- .75 + .5 + p$y[i]
  df2$y[cnt+3] <- .5  + .5 + p$y[i]
  df2$y[cnt+4] <- .75 + .5 + p$y[i]
  df2$y[cnt+5] <- .25 + .5 + p$y[i]
  cnt <- cnt + 5
  }

  if (p$value[i] == 4) {
  df2$x[cnt+1] <- .25 + .5 + p$x[i]
  df2$x[cnt+2] <- .25 + .5 + p$x[i]
  df2$x[cnt+3] <- .75 + .5 + p$x[i]
  df2$x[cnt+4] <- .75 + .5 + p$x[i]

  df2$y[cnt+1] <- .25 + .5 + p$y[i]
  df2$y[cnt+2] <- .75 + .5 + p$y[i]
  df2$y[cnt+3] <- .75 + .5 + p$y[i]
  df2$y[cnt+4] <- .25 + .5 + p$y[i]
  cnt <- cnt + 4
  }

  if (p$value[i] == 3) {
  df2$x[cnt+1] <- .25 + .5 + p$x[i]
  df2$x[cnt+2] <- .5  + .5 + p$x[i]
  df2$x[cnt+3] <- .75 + .5 + p$x[i]

  df2$y[cnt+1] <- .25 + .5 + p$y[i]
  df2$y[cnt+2] <- .5  + .5 + p$y[i]
  df2$y[cnt+3] <- .75 + .5 + p$y[i]
  cnt <- cnt + 3
  }

  if (p$value[i] == 2) {
  df2$x[cnt+1] <- .25 + .5 + p$x[i]
  df2$x[cnt+2] <- .75 + .5 + p$x[i]

  df2$y[cnt+1] <- .75 + .5 + p$y[i]
  df2$y[cnt+2] <- .25 + .5 + p$y[i]
  cnt <- cnt + 2
  }

  if (p$value[i] == 1) {
  df2$x[cnt+1] <- .5 + .5 + p$x[i]

  df2$y[cnt+1] <- .5 + .5 + p$y[i]
  cnt <- cnt + 1
  }
}

ggplot(df, aes(x= x, y = y)) + geom_tile(fill = "white", color = "black", size = I(.05)) +
  geom_point(aes(x = x, y = y), size = I(3), data = df2) + coord_equal()
ggsave(file = "jeff.png", width = 50, height = 38, dpi = 72 )

# End of Line