Images are dense matrixes, and have a certain numbers of rows and columns. They can have 1 (grey) or 3 (RGB) or 4 (RGB + alpha-transparency) channels.

The dimension of the image matrix is ( height, width, channels).

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from PIL import Image
import cv2
from sys import getsizeof
import tensorflow as tf

1. Load image files (.jpg, .png, .bmp, .tif)

  • using PIL
  • using matplotlib: reads image as RGB
  • using cv2 : reads image as BRG
  • imread: reads a file from disk and decodes it
  • imsave: encodes a image and writes it to a file on disk
#image = Image.open("images/freedom.png")
#plt.show(image)

Load image using Matplotlib

The Matplotlib image tutorial recommends using matplotlib.image.imread to read image formats from disk. This function will automatically change image array values to floats between zero and one, and it doesn't give any other options about how to read the image.

  • imshow works on 0-1 floats & 0-255 uint8 values
  • It doesn't work on int!
image = mpimg.imread("images/freedom.png")
plt.imshow(image)
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x7f8bd8cfd5d0>
print(image.dtype)
freedom_array_uint8 = (image*255).astype(np.uint8) #convert to 0-255 values
float32

Load image using OpenCV

image = cv2.imread("images/freedom.png")
#OpenCV uses BGR as its default colour order for images, matplotlib uses RGB 
RGB_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)# cv2.cvtColor() method is used to convert an image from one color space to another
plt.imshow(RGB_image)
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x7f8bd8beb3d0>

For this image, the matrix will have 600 x 400 x 3 = 720,000 values. Each value is an unsigned 8-bit integer, in total 720,000 bytes.

Using unsigned 8-bit integers (256 possible values) for each value in the image array is enough for displaying images to humans. But when working with image data, it isn't uncommon to switch to 32-bit floats, for example. This increases tremendously the size of the data.

By loading the image files we can save them as arrays. Typical array operations can be performed on them.

print (RGB_image.shape, RGB_image.dtype)
(600, 400, 3) uint8

Load image using keras.preprocessing.image

  • load_img(image): loads and decodes image
  • img_to_array(image)
image_keras = tf.keras.preprocessing.image.load_img("images/freedom.png") # loads and decodes image
print(type(image_keras))
print(image_keras.format)
print(image_keras.mode)
print(image_keras.size)
#image_keras.show()
<class 'PIL.Image.Image'>
None
RGB
(400, 600)

2. Image Processing

Dense Array

One way to store complete raster image data is by serializing a NumPy array to disk.

image04npy = 720,128 bytes

The file image04npy has 128 more bytes than the one required to store the array values. Those extra bytes specify things like the array shape/dimensions.

np.save("images/freedom.npy", RGB_image)
freedomnpy = np.load('images/freedom.npy')
print("Size of array:", freedomnpy.nbytes)
print("Size of disk:", getsizeof(freedomnpy))
Size of array: 720000
Size of disk: 720128

Storing one pixels takes several bytes.There are two main options for saving images: whether to lose some information while saving, or not.

JPG format

  • JPEG is lossy by deflaut

  • When saving an image as $*$.JPEG and read from it again, it is not necessary to get back the same values

  • The "image04_jpg.jpg" has 6.3 kB, less than the 7\% of $*$.npy file that generated it

  • cv2.IMWRITE_JPEG_QUALITY is between (0, 100), and allows to save losseless

cv2.imwrite("images/freedom_jpg.jpg", freedomnpy, [cv2.IMWRITE_JPEG_QUALITY, 0])
freedom_jpg = cv2.imread("images/freedom_jpg.jpg") 
plt.imshow(freedom_jpg)
<matplotlib.image.AxesImage at 0x7f8bd8b86c90>

PNG format

  • PNG is lossless

  • When saving an image as $*$.PNG and read from it again one gets the same value backs

  • cv2.IMWRITE_PNG_COMPRESSION is between (0, 1): bigger file, slower compression

  • freedom_png.png = 721.8 kB, close to freedomnpy

cv2.imwrite("images/freedom_png.png", freedomnpy, [cv2.IMWRITE_PNG_COMPRESSION, 0])
freedom_png = cv2.imread("images/freedom_png.png") 
plt.imshow(freedom_png)
<matplotlib.image.AxesImage at 0x7f8bd8b049d0>