Hi all. I’m sharing a little script I crafted that turns an input image into gray scale, and then makes a spiral to approximate it.
When run, the script prompts you to choose an image to process or use the Lena demo.
''' convert image to a big spiral
'''
dr1=3.0 # delta radius for inner spiral
dr2=3 # delta radius for outter spiral
lseg=4 # length of spiral segment treated as a line
nlayers=4 # NO. of layers to segment gray scale img
sigma=3 # radius for Gaussian blur
#--------Import modules-------------------------
import numpy as np
from PIL import Image
from PIL import ImageFilter
import matplotlib.pyplot as plt
import dialogs
import photos
#-------------Main---------------------------------
if __name__=='__main__':
#----------Read image-----
i = dialogs.alert('Image', '', 'Demo Image', 'Select from Photos')
if i == 1:
img = Image.open('test:Lenna')
else:
img = photos.pick_image()
img=img.convert('L')
# resize
newsize=(300, int(float(img.size[1])/img.size[0]*300))
img=img.resize(newsize,Image.ANTIALIAS)
print('Image size: %s' %str(img.size))
# blur
img=img.filter(ImageFilter.GaussianBlur(sigma))
# convert to array
img=np.array(img)
img=img[::-1,:]
# thresholding
layers=np.linspace(np.min(img),np.max(img),nlayers+1)
img_layers=np.zeros(img.shape)
ii=1
for z1,z2 in zip(layers[:-1],layers[1:]):
img_layers=np.where((img>=z1) & (img<z2),ii,img_layers)
ii+=1
img_layers=img_layers.max()-img_layers+1
# get diagonal length
size=img.shape # ny,nx
diag=np.sqrt(size[0]**2/4+size[1]**2/4)
figure=plt.figure(figsize=(12,10),dpi=100)
ax=figure.add_subplot(111)
# create spiral
rii=1.0
line=np.zeros(img.shape)
nc=0
while True:
if nc==0:
rii2=rii+dr1
elif nc<0:
rii=rii2
rii2=rii+dr1
else:
rii=rii2
rii2=rii+dr2
print('r = %.1f' %rii)
nii=max(64,2*np.pi*rii//lseg)
tii=np.linspace(0,2*np.pi,nii)
riis=np.linspace(rii,rii2,nii)
xii=riis*np.cos(tii)
yii=riis*np.sin(tii)
if np.all(riis>=diag):
break
# get indices
xidx=np.around(xii,0).astype('int')+size[1]//2
yidx=np.around(yii,0).astype('int')+size[0]//2
idx=[jj for jj in range(len(yidx)) if xidx[jj]>=0 and yidx[jj]>=0\
and xidx[jj]<=size[1]-1 and yidx[jj]<=size[0]-1]
xidx=xidx[idx]
yidx=yidx[idx]
# skip diagonal jumps
if len(yidx)>0 and yidx[0]*yidx[-1]<0:
continue
xii=xii[idx]
yii=yii[idx]
# pick line width from image
lw=img_layers[yidx,xidx]
# add random perturbation
lwran=np.random.random(lw.shape)-0.5
lw=lw+lwran
# randomize color
colorjj=np.random.randint(0,60)*np.ones(3)/float(255)
for jj in range(len(xii)-1):
# smooth line widths
lwjjs=lw[max(0,jj-3):min(len(lw),jj+3)]
if jj==0 and nc>0:
lwjjs=np.r_[lwjjs_old,lwjjs]
wjj=np.ones(len(lwjjs))
wjj=wjj/len(wjj)
lwjj=np.dot(lwjjs,wjj)
ax.plot([xii[jj], xii[jj+1]],
[yii[jj], yii[jj+1]],
color=colorjj,
linewidth=lwjj)
if jj==len(xii)-2:
lwjjs_old=lwjjs
nc+=1
ax.axis('off')
#ax.set_facecolor((1.,0.5,0.5))
ax.set_aspect('equal')
plt.show()