Girlfriend and I made an implementation and realization of Petros vrellis’ knitting.

## Numbers

– computing the thread path on a laptop: ~**10min**

– knocking 315 nails: ~**2h30**

– knitting 4000 nodes of 1300m of fishing line: ~**12h**

## Preparing the canvas

The first step is to knock and number evenly spaced nails on a circular canvas. We bought a 50cm canvas. At first, we wanted to put a nail every 1cm and by doing so we would have obtained a total of 157 nails, which we found out to be too low for good-looking results. Hence, we decided to go for a 5mm spacing and ended up with 315 nails.

## Computing the thread path

We found out that knitting 4000 nodes was a good tradeoff between our time budget and sharpness of the result.

For 4000 nodes, the thread path is represented as a list of 4000 nail indices in [0..314] and we want to compute the thread path that produces the input image.

We implemented a stochastic-optimization algorithm that generates a random path and randomly mutates it. If a random mutation improves the result the algorithm keeps it, otherwise it rejects it and tries again.

while(true)

{

// random mutation

node = rand() % **NumberOfNodes**;

current_nail = **thread_path**[node];

candidate_nail = rand() % **NumberOfNails**;

**thread_path**[node] = candidate_nail;

// if the error is smaller keep mutation, otherwise revert

float error = **computeError**(**thread_path**);

if(error < **current_error**)

**current_error**= error;

else

**thread_path**[node] = current_nail;

}

The algorithm converges after ~8000 successful mutations.

## The error metric

“Improving the result” means that the algorithm needs a way to compare the thread path to the input image, i.e. it needs an error metric implemented as **computeError() **in the pseudo-code.

This function:

– computes the image produced by the thread. It conservatively splats the thread in the image such that the value of each pixel in this image is the length of thread (in meters) covering the pixel.

– computes the L2 error between the input image and the current thread image. To make the images comparable it is important to normalize them before computing their difference. Doing so makes sure that we compute a solution proportional to the input and it makes the algorithm insensitive to the thread length. Indeed, the longer the thread, the darker the image, and we don’t want the error to depend on this.

## Choosing the thread diameter

The thread needs to be chosen carefully because its thickness impacts the darkness of the result. In order to find the appropriate diameter, we rasterized the thread (each pixel is either 0 or 1) at different resolutions:

1024×1024 | 2048×2048 | 4096×4096 |
---|---|---|

The 4096×4096 one yielded the best result. Our canvas has a diameter of 50cm and we thus needed a thread of diameter: 50cm / 4096 = 0.12mm. We found black fishing line of this diameter on Amazon. The predicted total thread length was 1300m so we ordered three 500m reels.

## Results

Fabrice Neyret made a full-shadertoy implementation of our Algorithm.