Algorithmic Art: An Evolutionary Model

Preface

I am currently presenting pieces made using this model in galleries! If you would like to view some of my pieces, please view my online gallery. If you would like to inquire about a custom piece, please feel free to contact me.

Introduction

When it comes to art, stick figures and tracing is the limit of my expertise (even coloring inside the lines was always a challenge for me). Even so, there was a niche category that interested me: algorithmic art. Better yet, generative art.

Algorithmic art is exactly what it sounds like; it is generally a visual form of art that designed by an algorithm. Typically, these pieces follow a generative model such as fractals or cellular automata. The use of an autonomous system to create an art piece can be defined as generative art due to its nature of design.

I personally think that these pieces, even when they look complex, follow very simple rules that simply cannot match a true art piece; humans are very good at seeing patterns, and consequently, the true beauty of an art piece is an individual’s interpretation of the artist’s style.

So where does that leave us? Well, I still want to create my own art pieces, and the only way that I will be able to do so is through algorithmic art. This leaves one solution: create a generative art model that uses a more complicated heuristic to create its pieces; ideally, this algorithm will create a specific art piece of my design, but its style will be unique to that particular piece.

In this article, I will explain my use of genetic algorithms to create beautiful art pieces which have a deeper complexity than most generative models.

If you would like a more detailed breakdown of genetic algorithms, click here.

Genetic Algorithms: A Brief Overview

A genetic algorithm in a type of evolutionary algorithm that mimics natural selection in its procedures; it is essentially an optimization algorithm for multivariable problems.

How does a computer algorithm mimic evolutionary techniques?

Genetic algorithms are loosely based on the idea of Darwinian evolution; the fittest members of a society will move on, adapt, and become better/stronger/etc. while the weaker ones die. Three elements are required in order for natural selection to occur:

  1. Heredity: children receive the properties of their parents. If members live long enough to reproduce, the traits are passed down to their children in the next generation.

  2. Variation: not only must there be variety within the population, but also a means to introduce new variation; this is known as our domain. No population can evolve without new combinations of traits.

  3. Selection: essentially our “survival of the fittest” ideology; there must be a mechanism by which some members of the population are more likely to pass their traits onto the next generation, allowing for the concept of elitism. When we are talking about evolutionary algorithms, there is typically some fitness function that is used to determine the fitness of all members of a population.

All genetic algorithms follow a similar series of steps, an iterative process if you will, to evolve a population:

  1. Population initialization: an initial population is randomly created. Within our code, we must create some data type (a genotype) that represents features of a particular member (the phenotype). These “genes” are representative of our members in a population.

  2. Selection: this is where Darwinian evolution is applied; we must evaluate our population and determine which members are fit to be parents and produce children for our next generation. There are two main steps in selection:

    1. Evaluate fitness: we evaluate the fitness of our members with a fitness function (we create this function to optimize certain parameters; for example, if our genes are random strings of letters and our goal is to create certain words/sentences, we create a fitness function that calculates how close our genes are to the target word/sentence).

    2. Create a mating pool: here we apply the idea of elitism; which members are more likely to pass on their traits to the next generation? From an algorithmic standpoint, we want to create a probabilistic model that permits “fitter” members to have a higher chance of reproducing than “weaker” members of a population.

  3. Reproduction: we want to create a new population based on the fittest members of the previous generation. In order to do this, we first use some crossover algorithm to create a new child from two (or maybe even more) parents. We then create a level of variation by allowing a small chance of mutation for each particular gene; this allows us to increase our search space, aka our domain.

That’s it! These simple concepts are all we need to create evolutionary optimization. But, how can we apply this to a piece of art?

Selecting a Programming Stack

Seeing as our end goal is to create visual art, I have decided to use the free graphical library Processing, which will allow us to use Java to create our sketches. Processing allows us to manipulate pixels on a canvas, as well as save our images to several formats such as .png, .jpeg, and .svg (this will be useful for this project).

Applying Genetic Algorithms to Art

First things first, we need to create a problem to optimize: how will we use evolution to optimize a piece of art? Well, one idea we can look into is shapes; a picture can essentially be broken down into shapes, and we can manipulate shapes using Processing to create a picture. In particular, narrowing down the type of shape will make it easier for selecting genotypes/phenotypes. For that reason, I am going to use triangles for this project.

Building a Phenotype/Genotype

So we have our phenotype, which is a triangle. We need a genotype that we can manipulate using Java that can represent our shape. To create a triangle in Processing, we need six data points for the triangle (three points of the triangle, which each have an x and y coordinate (x1, y1, x2, y2, x3, y3)) and four data points for the color (red, green, blue, alpha). Here is an example of what a triangle would look like:

Some code displaying how to draw a triangle to the canvas. Our fill() function takes in 4 values, and the triangle() function takes in 6.

Result of the triangle code shown.

One triangle won’t be enough to create detailed art, however. In order to create higher “resolution” pieces, we will create a cell which holds multiple shapes. This gives us the flexibility to add in multiple cells with multiple shapes (we will apply this feature to a recursive algorithm later to create different levels of abstraction!). For now, let’s create a 2x2 grid with 3 shapes in each for a total of 12 shapes:

High level code displaying the creation of three cells (note: initial shape count being set to three is not shown here).

Two columns with two rows of cells, each with three shapes initialized.

Creating a Fitness Function

Putting shapes randomly into cells won’t be enough to create a piece of art; we need to create some kind of fitness function that allows us to evolve our population towards a more specified goal. What if we compare the art piece we are creating to an image, pixel by pixel? This will be simple and accurate concept, but not easy to implement. We need to compare each pixel of the image to each pixel of our canvas, and find the sum of differences for the color value. Confusing? Let’s take a look at the code for this:

We loop through each pixel in the canvas, creating a two-dimensional index from the one-dimensional array of pixels that Processing provides (i.e. the pixels[] array). We get the red, green, and blue values for the target image as well as the image we are creating, and build a fitness score that is determined by how different each pixel is; the lower the fitness score, the more accurate our image.

We have a fitness function, let’s apply it to our canvas and see what it returns:

Fitness score for canvas is 30,218,204.

Not a great score… It’s time to start evolving our population so we can lower that fitness score.

Mutation and Selection: The Final Steps

Our genetic algorithm will be unique in the fact that we only have a population size of two: the parent and child. In this case, we don’t need a crossover function because our child can inherit the exact traits of the parent. From there, we can slightly mutate the child by some parameters, and get the score of the child; in this case, the parameters that can be changed include:

  • The x and y position of any point on any shape

  • The color/transparency of any shape

  • The possibility of adding/removing a shape

If the child is more fit than the parent, it becomes the parent. Otherwise, a new child is created. Theoretically, we can follow this logic until a point of convergence (or until we are satisfied, since I don’t think we will get a “perfect” child). Let’s implement this with some extreme parameters so we can see the parent and its mutated child:

Two canvases: a parent (right) and child (left). We can see the slight changes in shape/color to two triangles, as well as a triangle being removed.

Okay! We have a basic algorithm.… but we’ve come to the problem that we see with many pieces of generative art: high level of detail with low level of abstraction and an overall “computer-generated” look. We are reaching our target population, but how we are reaching there isn’t good enough. Building the design won’t be difficult now that we have all the building blocks; we just need to develop a new way to draw.

Building the Design Algorithm

Even a simple sketch is conceptually built different than ours. While our algorithm uses a left-to-right or top-down approach, most sketches start with large important features; the oval shape of a head before adding face features, the front of a house before adding doors and windows, etc. I believe the next step in our painting is implementing this ideology. As mentioned earlier in the genotype/phenotype section, the way we created cells will allow us to do so.

First of all, we will set the cell size to the size of the canvas and preset the amount of initial shapes in that cell. We will implement a split feature that allows us to create four new cells in place of the old cell. Now instead of generating each small cell, we start with a large cell and evolve that to fit the painting the best it can. We then add smaller shapes to fill in the details, going to whatever depth we’d like. Let’s run this new algorithm for several thousand generations with a depth of five (meaning five splits):

Can you guess the famous painting that has been recreated here? Notice the details that can be found even on a small screen; imagine the intricacies of a full scale painting! This particular piece is comprised of almost 2,000 triangles.

Conclusion

In this article I discussed my methods of generating art using a modified genetic algorithm. Thanks to the features of Processing, I can download an .svg file containing my art piece, allowing me to expand my canvas to any size; this allows me to create large pieces that allow the view to see the overall piece at an abstract level, as well as view the intricacies of the art piece up close with all of its details. To see some pieces that I have created, please view my digital gallery. If you would like to inquire about a particular piece, or have a new piece created, please contact me.

Previous
Previous

SoCeRC++: Source Code Recommendation For C++

Next
Next

Building a Poker Engine From Scratch in JavaScript