TD12: Image compression and loss of quality.¶

Vincent GODARD - V4- 29/01/2024

GIS and Remote Sensing - PhD curriculum¶

Debre Berhan University and University of Paris 8¶

Freely inspired by :

  • MOOC FUN MinesTelecom Introduction au traitement des images (in French) https://www.fun-mooc.fr/courses/course-v1:MinesTelecom+04044+session01/info

Sources:

  • Landsat Thematic Mapper (TM) data from September 10, 1987, West of Worcester, Massachusetts (from the https://clarklabs.org/download/)

  • scikit-image https://scikit-image.org/

  • matplotlib https://matplotlib.org/

  • numpy https://numpy.org/


Download required documents :

Compressed file to download => here.

1. Loading data and libraries¶

1.1. Loading data¶

Upload the following file from your storage area to the data directory (TD12/data) under this notebook is located (.ipynb):

- how87tm3.tif

- how87tm4.tif

This noteboock and the "data" directory will be at the same level in the tree, both under TD12.

1.2. Loading libraries¶

Some libraries are already preinstalled (e.g. Matplotlib). The Skimage library is not, and must be installed.

You then need to load them (Import function).

In [ ]:
# To install Skimage, delete the # (before the "!").
# !pip install scikit-image
 
## Loading libraries
    
import skimage # Image processing library
import skimage.io as io # Utility for reading and writing images in various formats (shortened to io).
import skimage.metrics # Utility allowing measurements between images.
import matplotlib.pyplot as plt # Library for plotting and visualizing data in graphical form (shortened to plt).
import numpy as np # Library intended to manipulate multidimensional matrices or tables.

## To find out the version of skimage

skimage.__version__ # warning to "." after skiimage

You may find it useful to take a look at the https://scikit-learn.org/stable/ or https://scikit-image.org/ libraries, some of which have their own wikis in French^^! : https://fr.wikipedia.org/wiki/Scikit-learn or https://fr.wikipedia.org/wiki/Scikit-image or even https://fr.wikipedia.org/wiki/NumPy.

2. Loading and displaying data¶

2.1. Loading data¶

Reading an image file centered on the Howe Hill region, West of Worcester in Massachusetts (USA). This is the TM4 band (PIR, near infrared) and TM3 (red band) of the Landsat Thematic Mapper (TM) of September 10, 1987.

Unlike TD11, the file format is no longer .jpg (compressed JPEG format, https://fr.wikipedia.org/wiki/JPEG) but .tif (compressed or non-TIFF format, https://fr.wikipedia.org/wiki/Tagged_Image_File_Format).

In [ ]:
## Reading with the imread() function before displaying

HOW87TM4 = io.imread('data/how87tm4.tif')

2.2. Displaying image content¶

In [ ]:
## Displaying the number of rows, columns and number of channels (if applicable)
## Using the .shape function of the .io module

print(HOW87TM4.shape)

## If you want to dress up the output (text between '', then "," before the .shape function on the HOW87TM4 variable)

print('(number of rows, number of columns):', HOW87TM4.shape)

We may also want to know the depth of our variable (its coding) by its type.

○ The type of a Python object determines what kind of object it is: https://docs.python.org/3/glossary.html#term-type

In [ ]:
## Displaying information

print('type :', HOW87TM4.dtype )

The type is an integer (unsigned integer 8bits) encoded on one byte (256 levels of gray, for example).

2.3. Displaying the HOW87TM4 image in grayscale¶

In [ ]:
## Displaying the image in gray level, using the imshow() function of the plt module:

plt.imshow(HOW87TM4, 'gray')

## To choose another color: https://matplotlib.org/stable/tutorials/colors/colormaps.html

## Write anything in place of 'gray', it generates an error message!
## At ValueError, in the list of colors, try others such as :
## viridis' (default color) or 'tab20c_r' to see the effect.
## Pay attention, it's case-sensitive (SHIFT/min)!

3. JPEG compression¶

Compression in one of the most common formats, JPEG (https://fr.wikipedia.org/wiki/JPEG).

3.1. Compressed image creation¶

Compressing the HOW87TM4 image to jpeg with a compression level between 1 and 100

In [ ]:
## Saving the compressed image in .jpg format

io.imsave('data/HOW87TM4.jpg', HOW87TM4, quality=50) # 50% compression

After compression, the two files need to be compared. The first step can be visual.

To the eye, they should still look very similar. Otherwise, the statistical indicators of similarity are likely to be very unfavorable!

In [ ]:
## Reading the image in .jpg format

JPEG4 = io.imread('data/HOW87TM4.jpg') # Reading the image assigned to the JPEG variable
plt.imshow(JPEG4, 'gray')

To the eye, there's no obvious difference!

3.2. Comparison of HOW87TM4 JPEG-compressed image with original TIFF image¶

Visual and statistical comparisons.

3.2.1. Visual comparison¶

Using the subplot() function of "matplotlib.pyplot" which allows you to organize different plots inside a display grid (https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot. subplot.html or in French https://courspython.com/tracer-plurieurs-courbes.html#display-de-plurieurs-traces-dans-la-meme-figure).

In [ ]:
## Display of compressed image and difference image

plt.figure(figsize=(15, 5)) # display of images in two sub-figures (vary the size if necessary
plt.subplot(121) # display of multiple layouts in the same figure (121/122 layout on one line)
plt.title('JPEG4 (apparent luminances, 256 gray levels') # titling to identify the image
plt.imshow(JPEG4, 'gray') # display function in matplotlib.pyplot

## Add legend
plt.colorbar()

diff1 = np.absolute(HOW87TM4-JPEG4) # calculation (with numpy) the absolute value of the difference between the two images (origin - compressed)
plt.subplot(122) # display of multiple layouts in the same figure (121/122 layout on one line)
plt.imshow(diff1) # show the difference image between HOW87TM4 and JPEG4

## Add legend
plt.colorbar()

plt.title('TIFF - JPEG4 (deviation in val. absolute. of luminances app.)') # add a title to the sub-figure with the MSE value associated with the difference image
plt.show() # Not necessary here to display successive results stored in memory, but avoids unnecessary text above images (like: Text(0.5, 1.0, 'TIFF - JPEG4 Difference'))

The spatial distribution of the different gap values (from blue to yellow) seems fairly even.

3.2.2. Statistical comparison¶

Use of MSE (Mean-squared error) as a statistical indicator of compression loss.

What is MSE [mean-squared error or mean squared error (MSE) https://fr.wikipedia.org/wiki/Erreur_quadratique_moyenne]? Go see the settings and the explanations by following this link: https://scikit-image.org/docs/stable/api/skimage.metrics.html#skimage.metrics.mean_squared_error.

In [ ]:
## Calculation of the mean square error (MSE) between the two images


mse = skimage.metrics.mean_squared_error(HOW87TM4, JPEG4) # calculation of the difference between the two images with skimage.metrics via MSE

MSE = f'{mse:.2f}' # MSE value with two decimal places


print(f" Value of the MSE (mean square error) between the two images: {mse:.2f}")

#print('Value of the MSE (mean square error) between the two images:', MSE)

As it is a raw value, it is difficult to know if this loss of information (deviation from the original image) is significant!

We will compare this MSE value with that obtained, in the next chapter, on another compression, PNG.

4. Comparison of the HOW87TM4 compressed PNG image with the original TIFF image¶

4.1. PNG compression¶

Save HOW87TM4 image with default compression level, when in PNG.

In [ ]:
## Save compressed image in .png format

io.imsave('data/HOW87TM4.png', HOW87TM4) # no compression level is defined here

After compression, it's time to compare the two files. First, visually.

When read, they should look very similar!

In [ ]:
## Read image in .png format

PNG4 = io.imread('data/HOW87TM4.png') # read image assigned to PNG variable
plt.imshow(PNG4, 'gray')

## Add legend
plt.colorbar()

To the eye, there's still no obvious difference!

4.2. Comparison of the HOW87TM4 PNG-compressed image with the original TIFF image¶

Visual and statistical comparisons.

4.2.1. Visual comparison¶

Using the subplot() function of "matplotlib.pyplot" which allows you to organize different plots inside a display grid (https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot. subplot.html or in French https://courspython.com/tracer-plurieurs-courbes.html#display-de-plurieurs-traces-dans-la-meme-figure).

In [ ]:
## Display of compressed image and difference image

plt.figure(figsize=(15, 5)) # displays images in two sub-figures (vary size if necessary)
plt.subplot(121) # display of multiple layouts in the same figure (121/122 layout on one line)
plt.title('PNG4 (apparent luminances, 256 grey levels') # titling to identify the image
plt.imshow(PNG4, 'gray') # display function in matplotlib.pyplot

## Add legend
plt.colorbar()

diff2 = np.absolute(HOW87TM4-PNG4) # calcul (avec numpy) la valeur absolue de la différence entre les deux images (origine - compressée)
plt.subplot(122) # display of several layouts in the same figure (121/122 = layout on a line)
plt.imshow(diff2) # displays image of differences between HOW87TM4 and PNG4

## Add legend
plt.colorbar()

plt.title('TIFF - PNG4 (difference in absolute luminance values).)') # add a title to the sub-figure with the MSE value associated with the difference image
plt.show() # Not necessary here to display successive results stored in memory, but avoids unnecessary text above images (like: Text(0.5, 1.0, 'Difference TIFF - PNG4').)

The spatial distribution of the different gap values (from blue to yellow) seems fairly even.

4.2.2. Statistical comparison¶

Using MSE (mean-squared error) as a statistical indicator of compression loss.

What is MSE [mean-squared error (MSE) https://fr.wikipedia.org/wiki/Erreur_quadratique_moyenne]? See the settings and explanations by following this link: https://scikit-image.org/docs/stable/api/skimage.metrics.html#skimage.metrics.mean_squared_error.

In [ ]:
## Calculation of the mean square error (MSE) between the two images

mse = skimage.metrics.mean_squared_error(HOW87TM4, PNG4) # calculation of the difference between the two images with skimage.metrics via MSE

MSE = f'{mse:.2f}' # MSE value to two decimal places

#print(f" MSE (mean square error) value between the two images: {mse:.2f}")

print('MSE (mean square error) value between the two images:', MSE)

So, no loss (MSE = 0) with PNG compression!

However, compare TIFF, JPEG and PNG file sizes in your data directory!

5. Would you be able to compress the HOW87TM3 image in JPEG and then in PNG and compare them successively with the original TIFF image?¶

Don't be surprised if the HOW87TM3 image is very dark. Its dynamic range is low. We'll see how to analyze and improve it in TD 14.

In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]: