Goulib.image

image processing made easy

Combines flexibility of PIL Python Imaging Library (Pillow) with the power of scikit-image embedded in an easy to use Image class

In [1]:
from Goulib.notebook import *
from Goulib.image import *

import PIL.Image as PILImage
In [2]:
lena_original=Image('../tests/data/lena.png') #Image can be init'ed from a path
In [3]:
from skimage import data
camera_original=Image(data.camera()) #or from an array
In [4]:
# Image has many "PIL compatible" methods, but they always return a result Image
# instead of working in-place :
size=(128,128)
lena=lena_original.resize(size)
lena_gray=lena.grayscale()
camera=camera_original.resize(size,PILImage.LANCZOS)

Rendering

In [5]:
lena #images have a default HTML representation
Out[5]:
In [6]:
from Goulib.table import Table # images can also be put in tables ! and they're responsive !
Table([[lena,lena_gray,camera],['lena','lena gray','camera']])
Out[6]:
lenalena graycamera

Image modes and Conversions

In [7]:
#Images have an attached immutable "mode" string:
h(str(lena)) #usually RGB(A) (float) for color images
h(str(lena_gray)) #gray images can be either F (float) or L (int)
Image(mode=RGB shape=(128, 128, 3) type=float64)
Image(mode=F shape=(128, 128, 1) type=float64)
In [8]:
h(modes) #supported modes are those from scipy + those from PIL (but in float instead of uint)
{1:Mode('bool',1x,[0-1], F:Mode('gray',1x,[0-1], U:Mode('gray',1x,[0-65535], I:Mode('gray',1x,[-32768-32767], L:Mode('gray',1x,[0-255], P:Mode('ind',1x,[0-65535], RGB:Mode('rgb',3x,[0-1], RGBA:Mode('rgba',4x,[0-1], CMYK:Mode('cmyk',4x,[0-1], LAB:Mode('lab',3x,[-1-1], XYZ:Mode('xyz',3x,[0-1], HSV:Mode('hsv',3x,[0-1]}
In [9]:
converters.edges() #a graph between modes
Out[9]:
OutMultiEdgeDataView([('bool', 'gray'), ('bool', 'rgb'), ('gray', 'bool'), ('gray', 'rgb'), ('rgb', 'gray'), ('rgb', 'rgba'), ('rgb', 'cmyk'), ('rgb', 'lab'), ('rgb', 'xyz'), ('rgb', 'hsv'), ('ind', 'rgb'), ('rgba', 'rgb'), ('cmyk', 'rgb'), ('lab', 'ind'), ('lab', 'rgb'), ('lab', 'xyz'), ('xyz', 'rgb'), ('xyz', 'lab'), ('hsv', 'rgb')])
In [10]:
#conversions from/to any mode are implemented by traversing the graph automagically
lena_conv=dict((mode, lena.convert(mode)) for mode in modes)
lena_conv['1']*=255 # multiply 0/1 image so we can see it
Table([[lena_conv[m],m] for m in sorted(lena_conv)]).transpose()
Out[10]:
1CMYKFHSVILLABPRGBRGBAUXYZ

note that displaying multi channel images assumes RGB(A) images, so for the above images we have:

  • LAB : L=Red, A=Green, B=Blue (low)
  • HSV : H=Red, S=Green, V=Blue
  • CMYK: C=RED (almost zero), M=Green, Y=Blue, K=Alpha transparency (hence the image is low contrast)

Color / Planes separation and reconstruction

In [11]:
lena_rgb=lena.split() #extract gray level images from each channel
images=[lena,lena_gray]+lena_rgb
Table([images],titles=['Lena','Gray']+[c for c in lena.mode]) 
Out[11]:
LenaGrayRGB
In [12]:
camera=camera.convert('F') #not all conversions are automatic yet ...
Image(lena_rgb+[-camera]) # merges color planes and use camera as alpha channel
Out[12]:
In [13]:
lena_lab=lena_conv['LAB'].split() #extract gray level images from each channel
images=[lena]+lena_lab
Table([images],titles=['Lena']+[c for c in lena_conv['LAB'].mode]) 
Out[13]:
LenaLAB
In [14]:
Image(lena_lab,'LAB').convert('RGB')
lena_conv['LAB'].convert('RGB')
Out[14]:
In [15]:
lena_gray*'cyan' #gray colors can be multiplied by a color to make a colorized image
Out[15]:
In [16]:
lena_gray.colorize('blue','yellow') #colorize between specified black and white colors
Out[16]:
In [17]:
colors=['Cyan','Magenta','Yellow','blacK']
cmyk=lena.split('CMYK') # converts from RGB to CMYK under the hood
cmyk2=[im.colorize(col) for im,col in zip(cmyk,colors)] 
Table([cmyk,cmyk2],titles=colors)
Out[17]:
CyanMagentaYellowblacK
In [18]:
#rebuild color image from colorized CMYK planes
cmyk2[0]-(-cmyk2[1])-(-cmyk2[2])-(-cmyk2[3]) #what a strange syntax ...
Out[18]:

Palette and colors reduction

optimal palette is computed automatically in Lab space from a k-means segmentation of a radom subset of pixels (see http://scikit-learn.org/stable/auto_examples/cluster/plot_color_quantization.html )

In [19]:
lenaP=lena.convert('P',colors=5) #image can be reduced to any number of colors
h(lenaP,lenaP.palette) # the optimal palette is computed automatically
 
 
 
 
 
In [20]:
#palette can also be explicitely specified
palette=Palette(['purple','peachpuff','indianred','brown','lightcoral'])
lenaP=lena.convert('P',colors=palette)
h(lenaP,lenaP.palette)
 
 
 
 
 

Dithering

In [21]:
Table([[lena.dither(method,n) for method in dithering] for n in (2,3,4)], titles=dithering.values())
Out[21]:
nearestrandomfloyd-steinbergphilipssierra litestuckiJarvis, Judice, and NinkeAtkinsonBurkes