A couple of years ago I started work on some code that would generate cool fractals and shapes inspired by the artist Alex Grey who does the artwork for the band Tool - who are awesome.
I didn't get around to publishing the code, however, as I felt there was something missing; zoom forward to now where we have DALL-E available via API, allowing AI variations of an image to be generated and the time is perfect to hook the code up and make some really cool images.
The overall goal of the program is to generate a base image from various fractal patterns and sequences such as the Fibonnaci spiral, Sierpinski Triangles, Honey Combs, Branching Trees etc. Then pass the image into DALL-E for it to imagine new variations of the image and display them in the application.
The name is based on the Tool song Lateralus; the musical structure of which was based around the Fibonacci sequence.
Push the envelope, watch it bendYou can grab the code from my GitHub. It should work on Linux x86/ARM and Windows.
Install requirements with:
pip install -r requirements.txt
If you are running on Windows you will need to follow the instructions here to install Ghostscript.
Setting up the API
- Go to OpenAI and create an account, generate and grab the API key from Account > API Keys.
- Copy the 'api_template.py' file under 'config' and call it 'api.py'
- Put the api key in the 'api_key' variable in api.py
Launch the code with:
python3 gui_launcher.py
Main GUI code
The GUI uses the Tkinter library. The application uses the turtle graphics program, which allows images to be created and manipulated on a Tkinter canvas.
The main class in this code is "TurtleManager" which creates the GUI and sets default variables and canvas settings. It has several functions such as "element_config", "lock_unlock_gui", "live_draw_checker", "change_theme" and "random_background" which are used to perform various actions on the GUI.
The program uses the OpenAI API to get variants for generated graphics and uses functions from the "ml.openai_api" module to do so. The GUI also allows users to change the theme of the canvas and to set a random background colour.
Tkinter setup code
This code creates a Tkinter GUI application. The main class in this code is "TkinterBase" which sets up the main Tkinter window, canvas, and turtle screen.
The class has a constructor method which takes in three arguments: "title", "width", and "height". The title argument is used to set the title of the Tkinter window, the width argument is used to set the width of the canvas, and the height argument is used to set the height of the canvas.
The constructor method creates a Tkinter master window and sets it to a variable called "master". It then sets the state of the master window to 'zoomed' using the state() method. In case of exception it sets to 'normal' to workaround; this is due to the fact the zoomed option will crash on Linux it seems.
It then creates a canvas widget and configures its width and height using the passed in arguments. It then packs the canvas to the left side of the master window.
It also creates a turtle screen with the canvas as its argument and assigns it to a variable called "screen". The class creates a singleton global variable called "TkinterBaseAccess" which is an instance of the TkinterBase class, so that other parts of the program can access the canvas, screen, width and height.
GUI items code
This creates several Tkinter variables such as IntVar, StringVar which are used to store integer and string values and used to update the GUI. These variables are used to store and manage various settings related to the turtle graphics, such as branch shortenby, branch angle, branch length, and so on. Allowing for differing configurations of the fractals being drawn.
The class has several functions such as "draw_sequence", "init_ml", "clear_screen", and "add_branch" which are used to perform different actions related to the turtle graphics on the canvas. The class also creates several labels, buttons, and progress bars to be used in the GUI, such as a button to draw, a button to initiate ML generation, a clear button, and a progress bar.
This has been split out into a separate class to keep the actual GUI layout and items in a different place than the main GUI setup and turtle controls, to allow for easier modification and additions.
Json file conversion
This contains a single function called "convert_b64_to_image" which is used to convert a Base64 encoded image from a JSON file to a PNG image file.
The function takes in two arguments: "file_name" and "openai_response". The "file_name" argument is used to specify the name of the JSON file that contains the Base64 encoded image. The "openai_response" argument is used to specify the JSON object that is loaded from the JSON file.
The function then returns the image_file variable containing the file path of the PNG image. It also resizes the image to match the original canvas.
This function is required because the data from DALL-E is returned as Json, thus needs converting to an image.
Open AI ML code
This code is a Python script that uses the OpenAI API to generate variations of an image. The main function in this code is "get_variants" which is used to call the OpenAI API and generate variations of an image using DALL-E's variants functionality.
Base turtle code
This defines a base class for all turtles that are used in the program. The class is called "BaseTurtle" and it contains all of the default settings that every turtle uses, as well as the step function that moves each turtle. Under this same folder there are further pieces of code defining the different types of turtles for different fractals.
The class has an init method that sets up and configures a turtle's default values. When a new turtle is created, this method is called and it takes several arguments such as speed, pensize, stamp, gradient_step, rand_pos, rendered.
The class has several other methods such as color_change, goto, and run methods. The color_change method is used to change the color of the turtle. The goto method is used to move the turtle to a specific position without leaving a trace. The run method is used to perform the specific turtles drawing actions.
The turtle shapes code also have reference links to where I got the code for creating the shapes from.
Fibonnaci core
This code defines a dataclass called FibonacciSeq
which is used to calculate the Fibonacci sequence. The class has three fields: current
, next
, and nterms
, which are all set to 0, 1, and 1000 respectively by default. The class also has a counter
and step
method. The counter
method increments the Fibonacci sequence by the value set in nterms
, while the step
method increments the sequence by 1. This class is used by the Fibonacci turtle for generating the Fibonacci sequence and using it for drawing the fractal shape.
Gradient generator
This code defines the Colours
class, which is used to generate a gradient of colours for the various fractal shapes drawn by the turtles in the program. The class uses the colorsys
module to convert hue values to RGB colour values. The class has a gradient_step
attribute, which determines the increment of hue change when the step_gradient()
method is called.
The class also has R
, G
, B
attributes, which are the Red, Green, and Blue colour values of the current colour. The hue
attribute is the current hue value. The __post_init__
method is used to set a random colour. The step_gradient()
method is used to increment the hue value and update the colour values, the color()
method is used to convert the hue value to RGB value and the random()
method is used to set a random colour.
This code is required to step through the spectrum of colours while drawing shapes and fractals using the turtles - as well as keep the last colour values each turtle used.
Over thinking, over analyzing separates the body from the mindThe GUI looks like this:
With the canvas on the left and the controls on the right, lets look at the control panel:
The screen controls of course enable drawing, the ML generation and clearing of the screen - below this is the turtle control panel which allows for additions of fractal patterns as well as the configurations for them. Allowing the user to change the size and depth of them etc.
There is a progress bar here also which will move when drawing/ML generation is taking place in order to let the user know something is happening, as well as freezing the buttons on the GUI during these processes.
Clicking 'Add' on one of these will instantly draw one of the shapes onto the canvas at a fixed position.
Below this is the canvas config - queuing allows multiple additions to be added without drawing them yet, only being displayed when the 'Draw' button is hit.
Random positions can also be set for each shape as well as a random background colour.
The 'Live Drawing' button will enable the user to see the shapes being drawn in real time by the turtle.
When the 'ML Generation' button is pressed it will send the image off to DALL-E via the Open AI API and create a variation of it, then return that variation and display it on the canvas over the original image.
The original image will be saved into '/images' with a timestamp, alongside the variation image, also with a timestamp.
And following our will and wind we may just go where no one's beenHere are a few images that I've managed to create:
Really cool stuff - the only trouble is that this is currently limited to whatever credits you have on the DALL-E API; I think they give about 18$ free for a limited time and after that you have to pay - so I may look into another API in future for a limitless free solution for generating new images.
Let me know what you think and if any modifications can be made to improve it!
Thanks for reading this far and keep an eye out for future projects...
Comments