Generative art (note) collection

generative art
art
Collecting fast notes on using #rstats and potentiall other things to generate visuals.
Author

Matt Crump

Published

November 10, 2022

Modified

August 4, 2023

New rating system?

I stumbled across Dan Mackinlay’s wonderful notebooks and blog the other day and was inspired by his post rating system. Dan emoji stamps his posts to indicate his assessment of amount of uncertainty, usefulness, roughness, and novelty for his posts. I might give that a whirl. But, as of right now I can’t figure out how to get custom emojis working for this blog, so words will have to do.

Expertise: Not much | Usefulness: Decent | Audience: notes to self

Some goals

  • search around and check out a few R packages for making generative art

  • Try them out here

  • Mess around on my own

  • Add more testing to this space over time (when I have time

  • Make options to generate blog header visuals, so that I can more quickly get into writing without having to bounce out and spend too much time making headers in Adobe Express (also fun).

Generative Rrrrt

I follow a lot of #rstats people, so I have some hunchs on where to start.

That should be enough to get started, and I’ll more later.

ambient

ambient makes visual noise (Pedersen and Peck 2022)! I am excited. I’m also trying to remember how to cite R packages in quarto.

First example from the ambient documentation.

library(ambient)
simplex <- noise_simplex(c(500, 1000), 
                         pertubation = 'normal', 
                         pertubation_amplitude = 40)

plot(as.raster(normalise(simplex)))

That’s fun. The output adds a border to the image, I’d like to turn that on/off.

library(imager)
simplex <- noise_simplex(c(1000, 500),
                         pertubation = 'normal',
                         pertubation_amplitude = 40)

save.image(as.cimg(simplex), file = "images/test.jpg")

Going for a full width picture.

knitr::include_graphics("images/test.jpg")

Add words on top

Tangent time. How to add a layer of words on top of an image. Need to be able to do this part in order to use generative art for header backgrounds.

  • Ugh, tried imager::draw_text() but clunky, and didn’t work.

  • let’s check out https://swarm-lab.github.io/Rvision/…That looks super cool, but it needs some extra libraries to run. Best come back and try it out some time for video or other fast visual processing.

  • time for magick

library(magick)
library(magrittr)
simplex <- noise_simplex(c(500, 1000),
                         pertubation = 'normal',
                         pertubation_amplitude = 40) %>%
  normalise() %>%
  as.raster() %>%
  magick::image_read() %>%
  magick::image_annotate(
    "IT TOOK ME WAY \n TOO LONG \n TO ACCOMPLISH \n THIS GOAL",
    font = 'Times',
    size = 100,
    color = "white"
  )

magick::image_write(simplex,
                    path = "images/test_magick.jpg",
                    format = "jpeg")
knitr::include_graphics("images/test_magick.jpg")

Changing font

Is easy…go for IMPACT

simplex <- noise_simplex(c(500, 1000),
                         pertubation = 'normal',
                         pertubation_amplitude = 40) %>%
  normalise() %>%
  as.raster() %>%
  magick::image_read() %>%
  magick::image_annotate(
    "IT TOOK ME WAY \n TOO LONG \n TO ACCOMPLISH \n THIS GOAL",
    font = 'Impact',
    size = 100,
    color = "white"
  )

magick::image_write(simplex,
                    path = "images/Impact.jpg",
                    format = "jpeg")
knitr::include_graphics("images/Impact.jpg")

Border around text?

Is easy…go for IMPACT

simplex <- noise_simplex(c(500, 1000),
                         pertubation = 'normal',
                         pertubation_amplitude = 40) %>%
  normalise() %>%
  as.raster() %>%
  magick::image_read() %>%
  magick::image_annotate(
    " IT TOOK ME WAY \n TOO LONG \n TO ACCOMPLISH \n THIS GOAL",
    font = 'Impact',
    size = 100,
    color = "white",
    strokecolor = "pink"
  )

magick::image_write(simplex,
                    path = "images/Impact2.jpg",
                    format = "jpeg")
knitr::include_graphics("images/Impact2.jpg")

Make it lighter

Squish the noise back a little bit

simplex <- noise_simplex(c(500, 1000),
                         pertubation = 'normal',
                         pertubation_amplitude = 40) %>%
  normalise(to = c(.7,1)) %>%
  as.raster() %>%
  magick::image_read() %>%
  magick::image_annotate(
    " IT TOOK ME WAY \n TOO LONG \n TO ACCOMPLISH \n THIS GOAL",
    font = 'Impact',
    size = 100,
    color = "white",
    strokecolor = "pink"
  )

magick::image_write(simplex,
                    path = "images/Impact3.jpg",
                    format = "jpeg")
knitr::include_graphics("images/Impact3.jpg")

plain color background

I might be into mono-color and text for blog headers. That should be simple enough now:

header <- matrix(1,nrow=500,ncol=1000) %>%
  as.raster() %>%
  image_read() %>%
  magick::image_transparent(color="white") %>%
  magick::image_background(color="#ffffcc") %>%
  magick::image_annotate(
    " IT TOOK ME WAY \n TOO LONG \n TO ACCOMPLISH \n THIS GOAL",
    font = 'Impact',
    size = 100,
    color = "white",
    strokecolor = "pink"
  )


magick::image_write(header,
                    path = "images/header.jpg",
                    format = "jpeg")

knitr::include_graphics("images/header.jpg")

custom fonts

Squiggligraphy

I made some custom fonts a while back, and have them loaded to my system fonts. Checking if they work here. Working [x].

header <- matrix(1,nrow=500,ncol=1000) %>%
  as.raster() %>%
  image_read() %>%
  magick::image_transparent(color="white") %>%
  magick::image_background(color="#e2eeee") %>%
  magick::image_annotate(
    " SQUIGGLIGRAPHY \n by Matt Crump",
    font = 'CrumpSquiggligraphy',
    location = "-40+100",
    size = 110,
    color = "black"
  )


magick::image_write(header,
                    path = "images/header2.jpg",
                    format = "jpeg")

knitr::include_graphics("images/header2.jpg")

Moebius

Trying out the Moebius font with a highlight layer.

header <- matrix(1,nrow=500,ncol=1000) %>%
  as.raster() %>%
  magick::image_read() %>%
  magick::image_transparent(color="white") %>%
  magick::image_background(color="#dcfcf9") %>%
  magick::image_annotate(
    " Moebius \n by Matt Crump",
    font = 'CrumpMoebius',
    location = "-15+155",
    size = 100,
    color = "white"
  ) %>%
  magick::image_blur(radius = 20, sigma = 5) %>%
  magick::image_annotate(
    " Moebius \n by Matt Crump",
    font = 'CrumpMoebius',
    location = "-20+150",
    size = 100,
    color = "black"
  ) %>%
  magick::image_border(color="lightgray",
                       geometry = "10x10")


magick::image_write(header,
                    path = "images/header3.jpg",
                    format = "jpeg")

knitr::include_graphics("images/header3.jpg")

Squish it with noise

This is fun. I accomplished my goal of making simple headers for blogs. I can see how spelling command over layers of pixel space is intriguing for a generative artist.

For my next trick, I would like to merge this basic header above with some noise from ambient. Not too much noise, just a little bit.

noise <- noise_simplex(c(500, 1000),
                         pertubation = 'normal',
                         pertubation_amplitude = 40) %>%
  normalise() %>%
  as.raster() %>%
  magick::image_read()

header <- matrix(1,nrow=500,ncol=1000) %>%
  as.raster() %>%
  magick::image_read() %>%
  magick::image_transparent(color="white") %>%
  magick::image_background(color="#dcfcf9") %>%
  magick::image_composite(noise,
                          operator = "blend", 
                          compose_args="10") %>%
  magick::image_blur(radius = 20, sigma = 20) %>%
  magick::image_annotate(
    " Moebius \n by Matt Crump",
    font = 'CrumpMoebius',
    location = "-15+155",
    size = 100,
    color = "white"
  ) %>%
  magick::image_blur(radius = 20, sigma = 5) %>%
  magick::image_annotate(
    " Moebius \n by Matt Crump",
    font = 'CrumpMoebius',
    location = "-20+150",
    size = 100,
    color = "black"
  ) %>%
  magick::image_border(color="pink",
                       geometry = "20x20")


magick::image_write(header,
                    path = "images/header4.jpg",
                    format = "jpeg")

knitr::include_graphics("images/header4.jpg")

16:9

What does 16:9 feel like? NOTE: this is the correct size for mastodon preview windows

noise <- noise_simplex(c(900, 1600),
                         pertubation = 'normal',
                         pertubation_amplitude = 40) %>%
  normalise() %>%
  as.raster() %>%
  magick::image_read()

header <- matrix(1,nrow=900,ncol=1600) %>%
  as.raster() %>%
  magick::image_read() %>%
  magick::image_transparent(color="white") %>%
  magick::image_background(color="#dcfcf9") %>%
  magick::image_composite(noise,
                          operator = "blend", 
                          compose_args="5") %>%
  magick::image_blur(radius = 20, sigma = 20) %>%
  magick::image_annotate(
    " Moebius \n by Matt Crump",
    font = 'CrumpMoebius',
    location = "+0+310",
    size = 150,
    color = "white"
  ) %>%
  magick::image_blur(radius = 20, sigma = 5) %>%
  magick::image_annotate(
    " Moebius \n by Matt Crump",
    font = 'CrumpMoebius',
    location = "-10+300",
    size = 150,
    color = "black"
  ) %>%
  magick::image_border(color="pink",
                       geometry = "20x20")


magick::image_write(header,
                    path = "images/header4_16x9.jpg",
                    format = "jpeg")

knitr::include_graphics("images/header4_16x9.jpg")

1.71

THIS PART IS WRONG, but part of my discovery process.

It seems that mastodon image preview is closer to 1.71 than 1.77 (16:9). So, I will use 1600x 935 pixels for blog headers. Mastodon does not seem to support “large” image cards, and the image preview is shown in a square. This is a test of an example header I might use with a title containing 10 words or so. The words will be roughly inside an inner square, but the header image will be a 1.71 rectangle.

This part is true.

Frown face: magick has a very nice add border function that does not respect image size, it adds a little bit to the image size, making it annoying to resize. Annoyed face.

This code adds a border, but does not expand the image. 16:9 shows equal border in the mastodon preview window. Also, hilariously long. First timer code.

noise <- noise_simplex(c(900, 1600),
                         pertubation = 'normal',
                         pertubation_amplitude = 40) %>%
  normalise() %>%
  as.raster() %>%
  magick::image_read()

logo <-  magick::image_read("images/crumplab-logos_black.png")
logo <- magick::image_scale(logo,"350")

header <- matrix(1,nrow=900,ncol=1600) %>%
  as.raster() %>%
  magick::image_read() %>%
  magick::image_transparent(color="white") %>%
  magick::image_background(color="#dcfcf9") %>%
  magick::image_composite(noise,
                          operator = "blend", 
                          compose_args="5") %>%
  magick::image_blur(radius = 20, sigma = 20) %>%
  magick::image_annotate(
    "This is a possible \n blog post title \n I might write",
    font = 'CrumpMoebius',
    location = "+10+10",
    size = 100,
    color = "white",
    gravity = "center",
  ) %>%
  magick::image_blur(radius = 20, sigma = 5) %>%
  magick::image_annotate(
    "This is a possible \n blog post title \n I might write",
    font = 'CrumpMoebius',
    location = "+0+0",
    size = 100,
    color = "black",
    gravity = "center",
  ) %>%
  magick::image_composite(logo,
                          operator = "atop",
                          gravity = "center",
                          offset = "+0+300")

border <- magick::image_blank(width = 1600-80,
                              height = 900-80)
border <- border %>%
  magick::image_border(color="pink",
                       geometry = "40x40")
header <- magick::image_composite(header,border,"atop")

magick::image_write(header,
                    path = "images/header5.jpg",
                    format = "jpeg")

knitr::include_graphics("images/header5.jpg")

References

Bache, Stefan Milton, and Hadley Wickham. 2022. Magrittr: A Forward-Pipe Operator for r. https://CRAN.R-project.org/package=magrittr.
Barthelme, Simon. 2022. Imager: Image Processing Library Based on CImg. https://CRAN.R-project.org/package=imager.
Ooms, Jeroen. 2021. Magick: Advanced Graphics and Image-Processing in r. https://CRAN.R-project.org/package=magick.
Pedersen, Thomas Lin, and Jordan Peck. 2022. Ambient: A Generator of Multidimensional Noise. https://CRAN.R-project.org/package=ambient.
R Core Team. 2021. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.