Art

Marshall Gallt

# Load an image into R (make sure your working directory is set!)

# Packages (for the entire project)
library(imager)    # image loading and processing
## Loading required package: magrittr

## 
## Attaching package: 'imager'

## The following object is masked from 'package:magrittr':
## 
##     add

## The following objects are masked from 'package:stats':
## 
##     convolve, spectrum

## The following object is masked from 'package:graphics':
## 
##     frame

## The following object is masked from 'package:base':
## 
##     save.image
library(dplyr)     # data manipulation
## 
## Attaching package: 'dplyr'

## The following objects are masked from 'package:stats':
## 
##     filter, lag

## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)   # data visualization
library(tidyr)     # data wrangling
## 
## Attaching package: 'tidyr'

## The following object is masked from 'package:imager':
## 
##     fill

## The following object is masked from 'package:magrittr':
## 
##     extract
library(ggvoronoi) # visualization
library(kableExtra)
## 
## Attaching package: 'kableExtra'

## The following object is masked from 'package:dplyr':
## 
##     group_rows
# Load an image into R
img <- load.image(file = "polarbear.jpg")

# Print the image object out
print(img)
## Image. Width: 1080 pix Height: 720 pix Depth: 1 Colour channels: 3
plot(img)

# Represent the image as a data frame
img_df <- as.data.frame(img)

# Show a table of the first 10 rows of the data frame
img_df %>% 
  arrange(x, y, cc) %>% # sort by columns for viewing
  filter(row_number() < 10) %>% # Select top 10 columns
  kable("html") %>%  # Display table in R Markdown
  kable_styling(full_width = F) # Don't take up full width
x y cc value
1 1 1 0.0039216
1 1 2 0.0039216
1 1 3 0.0039216
1 2 1 0.0039216
1 2 2 0.0039216
1 2 3 0.0039216
1 3 1 0.0039216
1 3 2 0.0039216
1 3 3 0.0039216
# Add more expressive labels to the colors
img_df <- img_df %>% 
  mutate(channel = case_when(
    cc == 1 ~ "Red",
    cc == 2 ~ "Green", 
    cc == 3 ~ "Blue"
  ))

# Reshape the data frame so that each row is a point
img_wide <- img_df %>%
  select(x, y, channel, value) %>%
  spread(key = channel, value = value) %>%
  mutate(
    color = rgb(Red, Green, Blue)
  )
# Plot points at each sampled location
ggplot(img_wide) +
  geom_point(mapping = aes(x = x, y = y, color = color)) +
  scale_color_identity() # use the actual value in the `color` column

ggplot(img_wide) +
  geom_point(mapping = aes(x = x, y = y, color = color)) +
  scale_color_identity() + # use the actual value in the `color` column
  scale_y_reverse() + # Orient the image properly (it's upside down!)
  theme_void() # Remove axes, background

# Take a sample of rows from the data frame
sample_size <- 2000
img_sample <- img_wide[sample(nrow(img_wide), sample_size), ]

# Plot only the sampled points
ggplot(img_sample) +
  geom_point(mapping = aes(x = x, y = y, color = color)) +
  scale_color_identity() + # use the actual value in the `color` column
  scale_y_reverse() + # Orient the image properly (it's upside down!)
  theme_void() # Remove axes, background

# Create random weights for point size
img_sample$size <- runif(sample_size)

# Plot only the sampled points
ggplot(img_sample) +
  geom_point(mapping = aes(x = x, y = y, color = color, size = size)) +
  guides(size = FALSE) + # don't show the legend
  scale_color_identity() + # use the actual value in the `color` column
  scale_y_reverse() + # Orient the image properly (it's upside down!)
  theme_void() # Remove axes, background
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.

# Create a Voronoi Diagram of the sampled points
ggplot(img_sample) +
  geom_voronoi(mapping = aes(x = x, y = y, fill = color)) +
  scale_fill_identity() +
  scale_y_reverse() +
  theme_void()

# Detect edges in the image
edges <- cannyEdges(img)
## Warning in cannyEdges(img): Running Canny detector on luminance channel
# Display the edges
plot(edges)

# Convert the edge image to a data frame for manipulation
edges_df <- edges %>%  
  as.data.frame() %>% 
  select(x, y) %>% # only select columns of interest
  distinct(x, y) %>% # remove duplicates
  mutate(edge = 1) # indicate that these observations represent an edge

# Join on the edges data
img_wide <- img_wide %>% 
  left_join(edges_df)
## Joining, by = c("x", "y")
# Apply a low weight to the non-edge points
img_wide$edge[is.na(img_wide$edge)] <- .05

# Re-sample from the image, applying a higher probability to the edge points
img_edge_sample <- img_wide[sample(nrow(img_wide), sample_size, prob = img_wide$edge), ]

# Re-create the voronoi diagram with the re-sampled data
ggplot(img_edge_sample) +
  geom_voronoi(mapping = aes(x = x, y = y, fill = color)) +
  scale_fill_identity() +
  guides(fill = FALSE) +
  scale_y_reverse() +
  theme_void() # Remove axes, background

# Re-create the scatter plot with the re-sampled data (add random sizing of circles)
ggplot(img_edge_sample) +
  geom_point(mapping = aes(x = x, y = y, color = color, size = edge * runif(sample_size))) +
  guides(fill = FALSE, size= FALSE) +
  scale_color_identity() +
  scale_y_reverse() +
  theme_void() # Remove axes, background