Message Boards Message Boards

Digital Circlism: arrangement of circles over an image

Posted 4 years ago

MODERATOR NOTE: this work is now a resource function: https://resources.wolframcloud.com/FunctionRepository/resources/DigitalCirclism/
full code and functions' definitions can be found in the attached notebook at the end of the post.


Introduction

Let' s see how to generate pictures like:

result

Initially, I got the idea from this site:

https://github.com/arihant-001/Circlism

But, I was not able to reproduce the results and my first algorithm was too slow. Then, I discovered this very interesting discussion:

https://mathematica.stackexchange.com/questions/40334/generating-visually-pleasing-circle-packs

But, it was not exactly like the first link.

After some experiments, and by mixing the ideas from the 2 previous links and some ideas of mine, I was able to generate the kind of pictures I wanted.

Preprocessing

First, we need to extract the edges of the picture. I have found that the following steps are generally giving a good result.

I am resizing the image so that it is not too big. Otherwise the algorithm will be very slow. There are some optimizations I could do.

srcImage = 
 ColorConvert[
  ImageResize[
   RemoveAlphaChannel[ExampleData[{"TestImage", "Girl3"}], White], 
   400], "RGB"]

I am applying a MeanShiftFilter. But you could try with other processing to reduce the noise. There is no rule. It just has to look good at the end.

segmented = MeanShiftFilter[srcImage, 13, 0.1]

filtered image

Finally, the edges are computed.

edges = ColorNegate@EdgeDetect[segmented]

Edges

Now, the first key idea : the Euclidean Distance Transform will give the distance of a point to the closest edge. When you have this distance, then you can draw a circle which will not cross any edge. Since distances will be > 1.0, you need an ImageAdjust if you want to display the result. I do it only as an illustration since this step is part of the main function.

DistanceTransform[edges] // ImageAdjust

EDT

Generation of the circles

The function below will try to place all the circles starting from the biggest to the smallest. The different scales to be considered are given by the list d.

d = {50, 20, 10, 5, 3, 2};

So, for instance, during the first pass, we will consider only the points with with an euclidean distance > 50.0. This euclidean distance is the radius of the circle to place at this point.

We may not be able to place all the circles because of overlap with the circles already in place. So, when a circle cannot be placed, it is resized during the next phase. All circles with radius > 50.0 will be resized to radius 50.0. If they still can't get a place, then during the next phase they will be resized to 20 ...

The overlap detection is the part to be optimized : I am comparing the circle to all of the already placed circles. Some partitioning of the plane may be useful to make this comparison quicker and avoid testing circles which are too far. In this version, it is the biggest limiting factor is you want to process big pictures.

result = circlism[d, edges];

The circlism function is returning a list of {position,radius}.

We use this list to draw the final pictures.

Two options are used by this function. "TimeConstraint" is set by default to 3 minutes. The image generation will stop after 3 minutes so you may not have all the circles.

"Pad" is set to 0.0 and controlling the padding between the circles.

Picture Generation

Many variations are possible.

In this first picture, we just overlay the disks on top of the picture. The color of the disk is the color of the picture pixel at the center of the disk.

Show[srcImage, 
 Graphics[{EdgeForm[Thickness[0.001]], 
   MapThread[{imgColor[#1], Opacity[0.9], Disk[#1, #2]} &, result]}]]

Img1

In this variation, we use an uniform background. I am generating this background with an ImageApply because I have observed that the Show is clipping the Graphics as it should when an image is used.

Show[uniformBackground[0.8], 
 Graphics[{EdgeForm[], 
   MapThread[{imgColor[#1], Disk[#1, #2]} &, result]}]]

Img2

In this other variation, we use the colFunc function which is using a background mask. For circles in the background, a random color from a palette is used.

Show[srcImage, 
 Graphics[{EdgeForm[Thin], 
   MapThread[{colFunc["Aquamarine", #1], Disk[#1, #2]} &, result]}]]

Img3

Why only use circles ?

Show[srcImage, 
 Graphics[{EdgeForm[Thin], 
   MapThread[{colFunc["Aquamarine", #1], RegularPolygon[#1, #2, 6]} &,
     result]}]]

enter image description here

Attachments:
11 Replies

enter image description here -- you have earned Featured Contributor Badge enter image description here Your exceptional post has been selected for our editorial column Staff Picks http://wolfr.am/StaffPicks and Your Profile is now distinguished by a Featured Contributor Badge and is displayed on the Featured Contributor Board. Thank you!

POSTED BY: EDITORIAL BOARD

Thank you.

I took a similar approach with TessellateGraphics:

https://resources.wolframcloud.com/FunctionRepository/resources/TessellateGraphics

though I never thought of using EdgeDetect to apply it images that were not already masks.

enter image description here

POSTED BY: Jon McLoone

Great. I'll play with your function.

And perhaps I'll push this work to the function repository when I have learnt how to do it.

Its pretty easy to submit items. Use the menu New/RepositoryItem/Function Repostory and just fill in the notebook.

If you can see an syntax extension that don't create backward compatibility, feel free to extend the source code of mine by editing https://www.wolframcloud.com/files/4793f5f4-937f-49ff-852b-633e518e2b5c?contentDisposition=attachment

POSTED BY: Jon McLoone

And it is finally a resource function !

Nice

POSTED BY: Jon McLoone

Congratulations! Your post was highlighted on the Wolfram's official social media channels. Thank you for your contribution. We are looking forward to your future posts.

POSTED BY: EDITORIAL BOARD

The algorithm is working well on video too:

https://vimeo.com/629924483

Very nice video! Is there a code for it? I wonder if it is possible to make an animated GIF.

POSTED BY: Vitaliy Kaurov

Here is a notebook. The code can be easily modified to change the style of the result.

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract