Genuary 2022: Self portrait​
​by Sander Huisman
Each year there are several challenges for generative arts in the month January called “Genuary” ( https://genuary.art/prompts ). This #genuary2022 the prompt is ‘self portrait’ I wanted to use a portrait photo and make some moving dots that make a loop.
Open the image, convert to grayscale, resize, get the data and scale it from 0–9. Get some point distributions in a 1*1 box for 0–9 points using LLoyd’s algorithm.
In[]:=
SeedRandom[1234];​​SetDirectory[NotebookDirectory[]];​​img=Import["2022_20.jpg"];​​img//=ColorConvert[#,"Grayscale"]&;​​img//=ImageResize[#,{100}]&​​data=Rescale[ImageData[img]];​​data*=9;​​pts=RandomReal[{-1/2,1/2},{#,2}]&/@Range[2,9];​​pts=ResourceFunction["LloydAlgorithm"][#,{{-1/2,1/2},{-1/2,1/2}},60]&/@pts;​​PrependTo[pts,{{0.0,0.0}}];​​PrependTo[pts,{}];​​​​Graphics[Map[Disk[#,0.1]&][#],PlotRange1/2,Frame->True]&/@pts
Out[]=
Out[]=

,
,
,
,
,
,
,
,
,

Based on the intensity of the pixels show 0–9 dots. Combine all dots in ‘d’
In[]:=
d=MapIndexed[With[{p=1.05pts[[Round[#1+1]]],c={1,-1}Reverse[#2]},(c+#)&/@p]&,data,{2}];​​d//=Catenate@*Catenate;​​d//Length
Out[]=
20043
Show the positions of d:
In[]:=
Graphics[Point[d]]
Out[]=
Find a tour of the points and visualize the tour:
In[]:=
SeedRandom[1234];​​{dist,is}=FindShortestTour[d];​​Graphics[{Point[d],Line[d[[is]]]},ImageSize1000]
Out[]=

Improve by swapping

As you can see, the shortest path tour still has some crossings in it (the tour is not perfect, but we can improve!). Some of them are adjacent, which we can easily swap:
Aborted it after a while because it takes forever :-)
​
Visualize the path by coloring it:
Let’s further improve the path by removing crossings, for that we need to write a function that detects if two (finite length) lines cross:
Find the crossings, and visualize them:
Show an example of a crossing, the idea is to reverse the green points of the tour, removing the crossing basically.
From the points, find crossing, reverse sections of the tour, and make sure swaps don’t affect future swaps, repeat until no more crossings:
Just to check: how many crossings:
That’s good news, no more crossing, let’s visualize it:
Build a frame from the points pts and some time that goes from 0 to 1:
Create images:
Export gif:
Total time it takes in {hour, minute}: