Anyway this type of algorithm could be implemented in G'MIC?

Ran across this via search. I know there’s a shapism preset, but was wondering if this type of algorithm could be implemented.

Also ran across a similar effort from Wolfram.

1 Like

Totally doable yes.
The main difference with the circlism algorithm already present in G’MIC, is that they use the distance function to locate the position of the largest circle to draw.
In G’MIC, this is something that can be done like this:

foo :
  shape_cupid 800
  100%,100%
  do {
    +distance[0] 0
    x,y,r:=xM,yM,min(50,iM)-2 rm.
    circle[1] $x,$y,$r,1,1
    circle[0] $x,$y,$r,1,0
    w[1]
  } while $r>1

giving this:

To make this faster on a larger image, it’s probably good enough to do it on random smaller crop taken at each iteration.

2 Likes

Second iteration:

foo :
  sp colorful,800
  +b. 1 slic. 128,3 +. 1 +g. xy,1 a[-2,-1] c norm. ==. 0 *[-2,-1] +!=. 0 ==.. 0
  100%,100%

  is_contours=1
  repeat inf {
    +distance[2] 0
    x,y,r:=xM,yM,min(40,iM)-2 rm.
    circle[3] $x,$y,$r,1,1
    circle[2] $x,$y,$r,1,0
    w[3]

    if $r<=2
      if $is_contours is_contours=0 +[2] [1]
      else break
      fi
    fi
  }

  +blend[0,3] shapeaverage0
  o. gmic_circlism.png

With the dog image:

1 Like

Version 3 (way faster) :

foo :
  sp colorful,1024 => img
  +b. 2 slic. 64,3 +. 1 +g. xy,1 a[-2,-1] c norm. ==. 0 *[-2,-1] +!=. 0 ==.. 0 => contours,mask

  nb_attempts=0
  repeat inf {
    x0,y0,x1,y1:="
      const N = 96;
      X0 = cut(round(u(w#$img) - N/2),0,w#$img - 1);
      Y0 = cut(round(u(h#$img) - N/2),0,h#$img - 1);
      X1 = cut(X0 + N,0,w#$img - 1);
      Y1 = cut(Y0 + N,0,h#$img - 1);
      [ X0,Y0,X1,Y1 ]"

    +z[mask] $x0,$y0,$x1,$y1 frame. 1,1,0 distance. 0
    x,y,r:=$x0+xM-1,$y0+yM-1,min(40,iM)-2
    rm.
    circle[mask] $x,$y,$r,1,0

    if !($>%100) w[mask] fi
    if $r<=2
      if narg($contours) +[mask] [contours] rm[contours]
      else nb_attempts+=1 if $nb_attempts>10 break fi
      fi
    else nb_attempts=0 fi
  }
  ==[mask] 0 +blend[img,mask] shapeaverage0

Took 12s on my machine for this 1024x1024 image

It’s probably not far from being usable as a new filter :slight_smile:

3 Likes

What I miss the most is the regularity we can find for instance in these images (manually done by the artist Ben Heine) :

Probably not easy to enforce this kind of regularity, if anyone has an idea…

1 Like

Perhaps contour detection and a spacing scheme based on gradient change in the locally steepest direction. These data could, in part, govern how you might set circle size in a particular neighborhood and align the contour they follow. I was dancing around this back in my Tiling days and don’t have to tell you that G’MIC has a rich tool set in this gradient/contour selection realm.

1 Like

I was thinking about doing this circle packing with a multi-resolution scheme.
My guess is that all circles found at a lower resolution should be more “aligned” in a finer scale, because their coordinates would be all multiples of a scale factor.

I’ll give a try tonight hopefully.

I find it interesting that Mr. Heine uses the rate of change in circle size to convey information about the surface. The hat band is presumably smooth; the variation in circle size there is slight. In contrast, the circles conveying information about hair vary a great deal. I can see how this draws you to a multi resolution scheme; rapidly varying regions like hair would wind up in one resolution band; smooth surfaces would dominate another band.

2 Likes

Unfortunately, it does not work as expected : at lower scales, many image regions are naturally smoothed out (by the downsampling) which leads to the apparition of large circles too early in those regions.

I have another idea though :slight_smile: Working with a single scale, it should be possible to improve the choice for a new circle by using the information of contours (and possibly orientation).
Will try that.

1 Like

My other idea doesn’t work either… :frowning:
So, I’ve replaced flat-colored circles with illuminated 3D spheres… :slight_smile:

4 Likes

I think to get regularity, one must utilize distance on cut contours, then each pixel represent distance away from a starting point, and divide that by contour distance multiplied by a value, and then create square blob. Finally insert circles in it. Think of 2d surface modeled in quad mesh akin to 3d mesh.

Got up to do my walk and run errands and came back and wow. Very cool stuff, David. Heine’s work is the motivation for this thread. You never dissappoint, David. Kudos. Hopefully it will be a GIMP/G’MIC preset soon. lol

Yes; asketh for too mucheth, but much appreciated. :slight_smile:

What I’ve toyed with in shapism, was to create masks if you will by running filters such as G’MIC’s paint or other dynamic filters and then using transparency to selection to (toggle mask select button and copy) and then paste and run blend shape average to colorize the dots based on the target. The mask then can have all kinds of drama so long as it can align with the target. Still, to get better dymamic results like what David shared here, just wasn’t possible with shapism alone. :slight_smile:

Tried copy/pasting code into the GIMP plugin (run sample code) but it fails, so I assume it can only work in CLI. Might try downloading the CLI version later. :slight_smile:

I’ve extended the algorithm to using ellipses rather than circles only :

5 Likes

Definitely cool; now for a GIMP plugin interface. lol

As a side, the ellipses remind me of easter eggs; hmmmm lol

:slight_smile:

Question, is alpha factored in here?

I don’t understand the question…

I’m asking if the 4th channel is factored or considered here. Like, is it used for getting the output of ellipse/circles or it can be used as empty background?

OK; got the code to work in GIMP/GMIC plugin by removing foo :. When I took the reference image out of the code, it would start running on the operation layer from GIMP but then it errors. Not sure how to pipe the layer into the code. Also, would like a transparent background color as opposed to black or just retain the mask. Still cool. :slight_smile: