The novice module provides a simple image manipulation interface for beginners. It allows for easy loading, manipulating, and saving of image files.
The novice module a standalone package via pip (image_novice). We are working with the folks over at scikit-image to get novice incorporated into the next release (it's currently in their Github repo).
Loading a picture is easy with the novice module. After importing, the open method returns a Picture instance that is visible in an IPython notebook.
In [2]:
from image_novice import novice
picture = novice.open("sample.png")
picture
Out[2]:
A picture knows its image format, where it came from, and its size.
In [3]:
print "Format:", picture.format
print "Path:", picture.path
print "Size:", picture.size
print "Width:", picture.width
We can easily resize the picture so that it's taller than it is wide.
In [4]:
picture.size = (200, 250)
picture
Out[4]:
A Picture is a collection of Pixel instances. We can iterate over the pixels and modify their color components individually. Below, we halve the red value of all pixels that are more than 50% red.
In [5]:
for pixel in picture:
if ((pixel.red > 128) and
(pixel.x < picture.width)):
pixel.red /= 2
picture
Out[5]:
A picture knows that it's been modified, which also resets its path to None.
In [6]:
print "Modified:", picture.modified
print "Path:", picture.path
Modifying a group of pixels is easy using slices. Below, we put a black box in the lower-left corner of the picture. Note that the novice module uses Cartesian coordinates (i.e., pixel 0, 0 is at the lower left).
In [7]:
picture[0:20, 0:20] = "black"
picture
Out[7]:
A Picture can be saved with a different format, and its corresponding properties are updated accordingly.
In [8]:
picture.save('sample-bluegreen.jpg')
print "Path:", picture.path
print "Format:", picture.format
print "Modified:", picture.modified
Manipulating small images pixel by pixel can be difficult.
In [9]:
blocks = novice.open("block.png")
print "Size:", blocks.size
blocks
Out[9]:
We can change how an image is displayed by increasing its inflation factor. An inflation factor of 10 means that a 10x10 square will be displayed for every real pixel in the image.
In [10]:
blocks.inflation = 10
blocks
Out[10]:
Note that this does not modify the underlying image. The block is still the same size underneath (10x10 pixels).
In [11]:
blocks.size
Out[11]:
Using slices, let's recolor the lower left square with yellow.
In [12]:
blocks[1:5, 1:5] = "yellow"
blocks
Out[12]:
We can change the inflation factor at any time!
In [13]:
blocks.inflation = 25
blocks
Out[13]:
By using slices and the image's size, we can change the border to violet.
In [14]:
blocks[:, 0] = "violet" # Bottom
blocks[:, blocks.height - 1] = "violet" # Top
blocks[0, :] = "violet" # Left
blocks[blocks.width - 1, :] = "violet" # Right
blocks
Out[14]:
Finally, let's swap the left and right halves of the image.
First, we copy the left half. Next, we overwrite the left half with the right half. Without the copy(), this would cause the temp variable to change as well. Finally, we overwrite the right half with the copied left half.
In [15]:
w = blocks.width / 2
temp = blocks[:w, :].copy() # Have to make a copy here explicitly!
blocks[:w, :] = blocks[w:, :]
blocks[w:, :] = temp
blocks
Out[15]: