Introduction
A few months ago, I found an art piece done by Petros Vrellis in which he weaves an image by looping a long strand of thread over a circular rim over and over again and ever since then, I couldn’t stop thinking about how cool his work was. I couldn’t for the life of me figure out how a human could convert a picture into a series of lines on a circular panel…until I realized that it might not be a human that does it.
My Attempt and Results
After a few days have passed since I saw his work, an idea popped out of my mind. This idea that I had was to recreate his work, all while sitting in the comfort of my chair. My idea was that a user can input any picture of any size, and an algorithm will take that picture, resize it, crop it, and finally add lines to the picture until an output forms. The idea seems feasible and even simple at the time. Then I started to think about the details.
The challenge I gave myself in this project was that I wasn’t allowed to refer to any other similar work done on the internet. This project was to be done from my knowledge of programming. As always, I started out planning on my sketchbook on how I would approach this project. Below are some of the more readable snippets of my sketch.
Once I have the idea in place, it was time to start coding. I first had to choose which language to code in. Since I have thought about using vectorization as a method to approach this problem and have a decent background in Python, that will be the language I’ll be using for this algorithm. Python may not be the most computationally efficient program, but it seemed to work just fine for my algorithm.
Fast forward to the next few months of off-and-on coding and many(many) head scratching moments, I have finally made a working simulation of Petros’ work. The results shown below are all done with the same parameters (6500 lines with 256 pins around the rim).
Original Picture: Monalisa
Comparison between transformed picture and my algorithm’s picture
Simulation of the thread art when done at 50 lines per frame
Original picture: Simba, chilling on my 3D printer
Comparison Image: Still as cute!
50 lines per frame GIF of the threading process
How It Works
The following parts will try to explain how the algorithm works and it will be the more technical part of this post. If you have no interest in how this algorithm work, you may skip straight to the conclusion.
My algorithm works by first having a user input an image, specifying the number of pins around the circumference and specifying the number of lines that the program will input (a higher number of lines and pins will output a higher ‘resolution’ image). There are a few other parameters that can be changed in the program, which includes the line thickness, the minimum line distances between each line (to prevent short lines), and also minimum steps the line has to take before going back to the same pin (to prevent an infinite loop). Tweaking and perfecting these parameters will allow for a better looking outcome.
After setting the parameters, the image defined will then undergo a series of transformations and filters to ensure the image is cropped to a circle and is in grayscale. The algorithm then stores the coordinates of all possible pins as well as the line distances between the two pins by applying the pythagorean theorem. The coordinate points along the line are then calculated and stored for all possible combination of lines.
The algorithm then loops to find the ‘best’ pin to form a line. The best pin is determined by summing the total black intensity along the line and picking the line with the highest intensity. Once the best pin is found, the coordinates are stored in a list and the intensity of the picture along the line is then reduced by a factor defined as the line thickness and the process repeats until the number of lines are reached.
The algorithm also takes a screenshot every X lines (defined by user) when the ‘GIF creation’ option is enabled. When the process completes, the frames are stored in a folder, and the ImageIO library is used to compile the frames into a GIF. The program also outputs a file which includes all the pin sequences if you plan to remake this in real life.
With the testing parameters in the results section, the simulation can be completed in around 1 minute when done with my low-end Lenovo laptop. However, when the GIF creation option is enabled, the time it takes skyrockets up to around 25 minutes. This may be caused by the inefficiencies of saving the frames before combining them to form a GIF.
Conclusion
Overall, I’m really satisfied with the the outcome of this project. If I were to take this to the next step, future plans may include an automated hardware which inputs the file that this algorithm provides, and automatically loops the thread for me. The code used in this project are open sourced can be found on my Github page so you can try it out yourself, provided you have the necessary libraries installed. Thanks for reading!