Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Turn image into spiral art
-
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()
-
@Jason, nice! Creates pretty artsy pictures, in the sense that recognizing the people in the original picture is not likely.
-
This is really pretty cool! I wonder if it might look even nicer if the whole picture was circular. (I haven't looked at the code in enough detail to see whether this is easy to do or not). But it's really fun to play around with this.