omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    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

    Pythonista
    3
    3
    2205
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Jason
      Jason last edited by

      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()
      
      
      mikael 1 Reply Last reply Reply Quote 1
      • mikael
        mikael @Jason last edited by

        @Jason, nice! Creates pretty artsy pictures, in the sense that recognizing the people in the original picture is not likely.

        1 Reply Last reply Reply Quote 0
        • omz
          omz last edited by omz

          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.

          1 Reply Last reply Reply Quote 0
          • First post
            Last post
          Powered by NodeBB Forums | Contributors