Edge aligning using gradients
My take on the rose:
gmic oellipse.gmic sp rose,1024 oellipse. 30,3,2.5,1,7 o. rose.png
Strong edges tend to orient better than soft-focus photographs:
Base image
gmic oellipse.gmic e_letter.png -blur_linear. 2,0,60 -d , -oellipse. 30,3,2.5,1.1,7 o. e_letter_oe.png
Never pass up an opportunity to foist yet another Goudy 1911 Bookletter ampersand on an unsuspecting world.
Base image
$ gmic oellipse.gmic amper_01.png r. 200%,200%,100%,100%,5 oellipse. 30,3,2.5,1,7 o. ampersand_ellipse.png
oellipse.gmic
#@cli oellipse : Spacefill a surface with edge-aligning ellipses; edges
#@cli : derived from selected images. 1. median factor: preprocess.
#@cli : blur neighborhoods with low local variance; force edges across
#@cli : boundaries between high variance. Larger ⇒ greater effect.
#@cli : 2. ellipse size. Larger ⇒ bigger ellipses.
#@cli : 3. edge sensitivity: lower admits only the most prominent edges.
#@cli : higher detects more edges. Too many edges and orientation is
#@cli : less clear.
#@cli : 4. Spread: Larger ⇒ spreads ellipses at greater step sizes
#@cli : along normals to edges.
#@cli : 5. Search passage count: Larger ⇒ increases the number
#@cli : of passes to find empty spaces to stick ellipses. Each pass
#@cli : tries to fit ellipses with 1/2 the radii of the previous pass.
#@cli : My image is black : Result of not finding edges. Try increasing
#@cli : median and/or edge sensitivity. Try pre-sharpening the image.
#@cli : It takes forever and a day to run!: Yep. Try fewer passes; smaller
#@cli : images. ≈5 minutes on 1024×1024 RGB with 7 passes. Later passes
#@cli : take longer. This with a Xeon(R) CPU E5-2630 v4 @ 2.20GHz running
#@cli : one thread (this toy does not multi-thread).
#$cli : $ image.jpg oellipse. 30,3,2.5,1,7 o. image_ellipse.jpg
oellipse: -skip ${1=10},${2=1},${3=3},${4=1.1},${5=1}
mfac=$1
efac=$2
esen=$3
sprd=$4
rcnt=$5
-name. img
+luminance.
-name. gray
-median[gray] $mfac
-newtile[gray] $esen,$efac,$sprd,$rcnt
-name. mask
-blend[img,mask] shapeaverage0
#@cli newtile : Make a partition (tiling) map of an image.
newtile:
-check "${1=3}>=0 && \
${2=1.0}>=0.05 && \
${3=1.5}>=0.25 && \
${4=1}>0"
-echo[^-1] "Creating a partition map of selected images."
edgesen={$1/100}
tsize={$2*0.025*sqrt(w^2+h^2)}
spread=$3
rcnt=$4
-name. metric
-remove_opacity[metric]
-gradient_norm[metric]
-blur[metric] 1
-ge[metric] {$edgesen*abs(iM-im)}
-distance[metric] 1
+gradient. xy
-append[-2,-1] c
-vector2tensor.
-name. orienter
[-1],[-1],1,1,[-1]
-name. plottingfield
-repeat $rcnt
-echo "Pass\ "{$>+1}
[metric]
-name. truedistance
-round[truedistance] {$spread*$tsize}
-fill[truedistance] ">
abs(i-j(1,1,0,0,0,1))>"{0.5*$spread*$tsize}"?
1: abs(i-j(1,0,0,0,0,1))>"{0.5*$spread*$tsize}"?
1:0"
0
-name. pstack
-eval[truedistance] ">
if(0<i(x,y),
da_push(#$pstack,[x,y,$tsize,$tsize,$tsize]);
run('plot_ellipse'))"
-remove[truedistance]
-if w#$pstack==0
-echo "Plotting field seems filled"
-break
-else
tsize:=0.5*$tsize
-remove[pstack]
-fi
-done
-keep[plottingfield]
-fill[plottingfield] i(x,y)==1?255:0
plot_ellipse:
cx,cy,er,pw,ph:=da_pop(#$pstack)
offw={round($pw/2,1,0)}
offh={round($ph/2,1,0)}
rad={round($er/2,1,0)}
estats={V=I(#$orienter,$cx,$cy);eig([V[0,2],V[1,2]])}
+crop[plottingfield] {$cx-$offw},{$cy-$offh},{$cx+$offw},{$cy+$offh},2
-name plotspot
-if (ia#$plotspot)<-0.875
-ellipse[plottingfield] $cx,$cy,$rad,{0.75*$rad},{es=[$estats];rad2deg(atan2(es[3],es[2]))},1,1
-echo "Plot Ellipse: "$cx,$cy
-echo "Ave: "{ia#$plotspot}
-echo "eigens: "{[$estats][0,2]}
-fi
-remove[plotspot]
Time to walk Vinny.
EDIT: Documented script listing.
More extensive documentation on making a partition map in Cookbook article Tiled Art. Have fun.