Generating Icons with Pixel Sorting

14/01/2017

Many sites these days provide randomly generated images for avatars if the user hasn't uploaded their own image. For example Github provides identicons which are generated using the hash of the username. These sorts of random icons are also useful for other purposes - on my most recent project, ./code --poetry I wanted to try generating random abstract icons to identify different poems. Here are a selection of the final results:

As you can see each one is very unique with its own character. Like with the Github identicons, I wanted to make it clear that the icons were computer generated, keeping the abstract, computational, pixelated look. But because these icons were also going to be used to represent poems I wanted to create icons which were naturally emotive and could be easily matched with poems that seemed to portray similar feelings. To do this I took inspiration from Movie Barcodes and pixel sorting - both of which seem to so easily capture the emotion of an image in an abstract way.

But this kind of glitch art is often only as good as the source image - using random images from google was unlikely to produce anything nice. Luckily an almost endless supply of incredible photography exists via Flikr's best of the week section. This gives us a constant source of images with beautiful colors and interesting compositions.

I started by crawling the best of the week page with Python and extracting all the links using Beautiful Soup.

from urllib.request import Request, urlopen
from bs4 import BeautifulSoup

flikr = 'http://www.flickr.com'
header = {
    'User-Agent':
        'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 '+
        '(KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36'
}
    
requ = Request(flikr+"/explore/interesting/7days/", headers=header)
soup = BeautifulSoup(urlopen(requ).read())
imgs = soup.findAll('img', "pc_img")

For each link on the page we can get the link url, and modify it a little bit to load up the page containing the smallest version of the image. We can then download the image to a temporary file and using Numpy/Scipy/Pillow we can resize/pixelate the image and pixel sort it with a few simple functions.

for qi, query in enumerate(imgs):
        
    requ = Request(flikr+query.parent['href']+'sizes/s/', headers=header)
    soup = BeautifulSoup(urlopen(requ).read())
        
    requ_img = Request(soup.findAll('img')[2]['src'], headers=header)
    
    import tempfile
    
    f = tempfile.TemporaryFile()
    f.write(urlopen(requ_img).read())
    f.seek(0)

    import numpy as np
    import scipy.misc as misc

    img = misc.imread(f)
    img = misc.imresize(img, (16, 16), 'nearest')
    img = np.sort(img, axis=0)
    img = misc.imresize(img, (64, 64), 'nearest')
    misc.imsave('icon_%03i.png' % qi, img)
        
    f.close()

And that's it! The best of the week page gives you different results every time so put the whole thing in a loop and enjoy your new set of pixel sorted icons. Just remember to crawl responsibly!