Visualizing String Art

For my undergraduate capstone in Computer Science, I chose to pursue an independent project based on the concept of String Art. String Art is a labor-intensive art-form, characterized by a thread that loops around nails on a board to create patterns or representational forms.

In this article, I provide an overview of the tools and techniques I used to devise a software algorithm to drawing string art, along with my results and take-aways.

Project Scope:

My goals for this project were to:

1. Develop an algorithmic technique for automating string art
2. Emulate the physical logic of string art—i.e. determine and place nails onto a canvas, to loop around with a single and continuous string

sherlock
Source: Laarco Studio

Deliverable:

Software that takes digital images as input and outputs subsequent 2D string art visualizations.

Tools:

Due to the computation-intensive requirements of this project, I decided to use OpenCV—a computer vision programming library optimized for image processingwhich uses Intel’s Integrated Performance Primitives for GPU acceleration. I used the OpenCV-Python bindings to leverage NumPy for matrix operations, and its Matplotlib library for processing arrays to images.

Process:

To devise my algorithmic strategy, I conceptually deconstructed the making of string art into two constituent parts: drawing contours (with nails), and filling in values (with recursive thread loops).

Screen Shot 2018-04-19 at 10.42.44 PM
Contour (the outline of a form) + Value (range from white to black) =   Drawing

Contours

In the context of string art, drawing contours requires breaking an image into its outlines, and then placing nails at optimal intervals. I began this step by testing on saturated illustrations containing stark lines. For detecting the outlines, I used an optimized no-parameter Canny Edge Detection method. Additionally, I used an OpenCV method called Good Features to Track to place points on the canny output.

Screen Shot 2018-04-19 at 11.10.07 PM
Edge detection and point allocation on a sample image

To connect these points from a single string such that every point was looped just once, I quickly realized I required a nearest-neighbor technique to determine the next closest neighbor at any point. I subsequently used a KD Tree and KNN search to achieve this.

Screen Shot 2018-04-19 at 11.11.01 PM
Drawing edge points randomly versus based on shortest-distance to each other

While using a KNN tree to draw contours (right) added time complexity, it yielded significantly better contours compared to an unordered traversal of points (left).

Values

In order to create light and dark values, I decided to allocate additional nails onto the canvas based on average values of a region for denser string loops. To break an image into its value-regions, I used Delaunay Triangulation which effectively splits points into triangles, favouring regular triangles over ‘skinny’ ones.

Generating these triangles also allowed me to calculate midpoints, values of which could be read to get an approximation of the region value. This proved to be sufficient, and exponentially more efficient than calculating exact averages of pixel values from triangle areas. I also calculated the middle value of every input image, assigning nails to only midpoints with darker values, as demonstrated below:

Screen Shot 2018-04-19 at 11.22.20 PM
Image split into Delaunay Triangles, and midpoints added to triangle with ‘dark’ midpoint values

At this point, I started working on actual images. Dark string regions require both additional nails and denser looping. In large dark regions, such as the clothing in the image below, midpoint nails did not suffice and more points were required. One way to do this would have been to create a random but controlled Poisson distribution inside these triangles.

However, I implemented a much simpler solution by adding a ‘noise’ filter over every input image. The added noise—made using the lower quartile pixel value—produced contrast in very dark regions; in lighter regions, middle-value noise did not create enough contrast for dark-point detection.

Screen Shot 2018-04-19 at 11.26.06 PM
Noise filter creating a distribution of points visible on only dark regions (midpoints highlighted in red)

Results and Conclusion

Combining all the aforementioned results allowed successful and optimized string art visuals.

screen-shot-2018-04-19-at-11-32-49-pm.png
Screen Shot 2018-04-19 at 11.31.57 PM
Screen Shot 2018-04-19 at 11.32.04 PM

Future goals:

This was a fun extension of several familiar tools and concepts.

In terms of areas for improvement, midpoint values can be used to loop the farthest points in dark triangles and closest points in light triangles. Doing so would yield much starker regions and better utilize looping as opposed to nail placement for creating dark values. While automation cannot (and should not) replace the ingenuity of an artist, further development of this algorithm could lead to very realistic results.

Mentored by faculty advisor Bret Jackson, with thanks to Satya Mallick for Delaunay Triangulation, and Adrian Roseblock for Canny Edge Detection methods. Special thanks to Laarco Studio, and fellow artist Petros Vrellis for inspiring this project.