I am writing you another ipython notebook because it is really, extremely cool. This nb uses ipythonblocks (written by the amazing Matt Davis), which is a visualizing system that uses little colored squares. It is especially useful when explaining the flow of code execution, cause it makes it really easy to see the process an algorithm goes through by watching how certain squares light up appropriately.
In this letter, I am modifying an ipynb that Matt wrote. His nb converted a jpg of Starry Night into a text file of pixels and their colors, and then converted that text file into an ipython blocks grid. Basically, the grid draws hundreds of little tiny blocks like a mosaic, until it depicts a (low resolution) version of Starry night.
Naturally, I needed to rework this project so it drew a picture of us.
So, here goes... Note that anything with the # sign in front of it is a comment for you. :]
#import a package that works with jpg images
from PIL import Image
#also import ipythonblocks
import ipythonblocks
#create an image object using a picture of us
im = Image.open('sare2.jpg')
#check what the size of the image is
im.size
(612, 816)
The original picture of us is really too large to draw in ipython blocks, so we can resize it to make our job a bit easier.
#resize, keeping the general dimensions; 1/4 of original size
im = im.resize((153, 204), Image.ANTIALIAS)
Now we have an image we can work with! We need to get all of its color data. So, for every single pixel, we need a (red, blue, green) value.
#thank goodness, the package we imported before can do all that work for us
imdata = im.getdata()
#check and see what the first (r, g, b) value is
imdata[0]
(71, 22, 6)
#we can use blocks to see what that first color is
ipythonblocks.show_color(imdata[0][0], imdata[0][1],imdata[0][2])
So, we can see what the first color is. Just for fun, let's see what some other random colors are in the picture. In order to do so, we need to know how many pixels there are that we can choose from in this picture. Then, we can just pick some random numbers to check.
#how many pixels are there in this image?
len(imdata)
31212
import random
for i in range(10):
val = random.randint(0,31212)
print "The random pixel is:", val
ipythonblocks.show_color(imdata[val][0],imdata[val][1],imdata[val][2])
The random pixel is: 27958
The random pixel is: 25832
The random pixel is: 9488
The random pixel is: 21903
The random pixel is: 17372
The random pixel is: 9156
The random pixel is: 5463
The random pixel is: 10927
The random pixel is: 4298
The random pixel is: 21359
Well, that's really awesome. We should paint a room in our house those colors some day. They look so nice together. Hehe.
But now it's time to move on to drawing the image of us! No more stalling.
#import packages that we will need
import os
import itertools
#this code is stuff matt wrote
#I think it makes a sare2.txt file.
with open('sare2.txt', 'w') as f:
s = ['# width height', '{0} {1}'.format(im.size[0], im.size[1]),
'# block size', '4',
'# initial color', '0 0 0',
'# row column red green blue']
f.write(os.linesep.join(s) + os.linesep)
for ((row, col), colors) in itertools.izip(itertools.product(xrange(im.size[1]), xrange(im.size[0])), imdata):
things = [str(x) for x in (row, col) + colors]
f.write(' '.join(things + ['\n']))
#indeed, it does. this block just shows what is in the file.
#but I'm still not sure why we need this file.
#I don't see it referenced later.
#but Matt wrote it so I'm leaving it in cause he's amazing
!head sare2.txt
# width height 153 204 # block size 4 # initial color 0 0 0 # row column red green blue 0 0 71 22 6 0 1 82 21 7 0 2 116 41 9
Time to make a grid! Once we make the grid, we can populate it with the colors in imdata from above.
grid = BlockGrid(153, 204, block_size=3, lines_on=True)
for block, colors in itertools.izip(grid, imdata):
block.rgb = colors
grid
Do you see all the little tiny squares?!!!! So cool, right. Kudos to Matt for making a package that can be used for writing a love letter.
Let's take out the little white lines between every block though, so you can see us better:
grid2 = BlockGrid(153, 204, block_size=3, lines_on=False)
for block, colors in itertools.izip(grid2, imdata):
block.rgb = colors
grid2
And there we are, looking so happy and in love. I love you, Sarah.