This notebook goes with a blog post:
In general, you can go one of two ways with images:
PIL
, pillow
(a port of PIL
).matplotlib
or scipy
.In the first category, we'll take a look at the Python Imaging Library. The main points about this library:
In the second category, we'll look at reading and writing images with matplotlib.image
, scipy
, and scikit-image
. All of these tools use PIL
behind the scenes for some of their functionality. The main features of matplotlib.image
:
PIL
.scipy
.This post uses data from this tweet by Prof Chris Jackson (Imperial College London). I don't know anything about the data. I doubt it has an open licence, but it's on Twitter, so...
We'll start with the usual prerequisites for our notebooks:
In [1]:
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
In [2]:
from PIL import Image
im = Image.open("../data/EChTISYWkAA6_DV.jpeg")
In the notebook, the repr
of this Image
object is a convenient display of the image:
In [3]:
im
Out[3]:
Notice that the size (not shape
!) is reported as columns × rows, so it's different from a NumPy array, which is rows × cols.
In [4]:
im.size
Out[4]:
In [5]:
np.array(im).shape
Out[5]:
(The 3rd dimension there is the channel: one each for red, green and blue.)
We can resize this image, but doing this while maintaining the aspect ratio is a bit fiddly becaue you have to compute the new dimensions yourself.
In [6]:
w, h = im.size
aspect = h / w
new_w = 200
new_h = int(new_w * aspect) # Has to be an int.
im = im.resize((new_w, new_h), Image.ANTIALIAS)
im
Out[6]:
You can save having to compute the new image size with the thumbnail
method but be careful — it resizes the image in place. So I'l do it on a copy:
In [7]:
temp = im.copy()
temp.thumbnail((64, 64), Image.ANTIALIAS)
In [8]:
temp
Out[8]:
We can plot this little image and see that it's now pixellated at any reasonable size:
In [9]:
plt.imshow(temp, interpolation='none')
Out[9]:
(Note in passing that we can pass an Image
object to imshow
. This is because it presents a NumPy-like interface. It's not an array though.)
We can ask imshow
for some more sensible interpolation:
In [10]:
plt.imshow(temp, interpolation='bicubic')
Out[10]:
In [11]:
rgb = np.array(im)
red_channel = rgb[:, :, 0]
plt.imshow(red_channel, cmap='gray')
Out[11]:
Note that NumPy doesn't implicitly care about the values:
In [12]:
np.max(red_channel)
Out[12]:
In [13]:
red_max1 = red_channel / 255
plt.imshow(red_max1, cmap='gray')
Out[13]:
But if you convert back to a PIL Image
, it cares. In fact, it won't even accept our decimal numbers in the 0–1 range:
In [14]:
im_red = Image.fromarray(red_max1)
im_red
# This should throw an error.
Out[14]:
We have to cast them to unsigned 8-bit integers (i.e. integers in the range 0 to 255):
In [15]:
im_red = Image.fromarray(np.uint8(red_max1 * 255))
im_red
Out[15]:
In [16]:
# Your code here...
In [17]:
import requests
from io import BytesIO
url = "https://pbs.twimg.com/media/EChTISYWkAA6_DV?format=jpg&name=large"
r = requests.get(url)
im = Image.open(BytesIO(r.content))
In [18]:
im
Out[18]:
In [19]:
import matplotlib.image as mpimage
img = mpimage.imread("../data/EChTISYWkAA6_DV.png")
In [20]:
type(img)
Out[20]:
In [21]:
img.dtype
Out[21]:
A nice feature of imread
is that it will accept a web URL as well as a filename:
In [22]:
img = mpimage.imread("https://pbs.twimg.com/media/EChTISYWkAA6_DV?format=png&name=large")
img.dtype
Out[22]:
You can load a JPEG, but matplotlib
will use PIL
behind the scenes. PIL
loads images as 8-bit unsigned integers in [0, 255], so that's what you'll end up with.
In [23]:
img = mpimage.imread("../data/EChTISYWkAA6_DV.jpeg")
In [24]:
img.dtype
Out[24]:
Notice we have an h × w × 3 array — this is an RGB image. PNGs often have a 4th channel, alpha or A, which holds opacity.
plt.imshow()
plots 3-channel arrays like this in colour:
In [25]:
plt.figure(figsize=(6, 10))
plt.imshow(img)
Out[25]:
We can plot only the red channel (say), and apply false colour via a lookup table:
In [26]:
plt.figure(figsize=(6, 10))
plt.imshow(img[..., 0], cmap='gray')
plt.colorbar(shrink=0.67)
Out[26]:
Let's look at the histogram for this channel:
In [27]:
_ = plt.hist(img[..., 0].ravel(), bins=128)
In [5]:
import skimage
skimage.io.imread("https://pbs.twimg.com/media/EChTISYWkAA6_DV?format=png&name=large")
Out[5]:
© 2019 Agile Scientific, licensed CC-BY, please share this work.