Avantages et inconvénients des formats de fichiers image#

Lorsqu’on travaille avec des données d’images de microscopie, de nombreux formats de fichiers circulent. La plupart des fabricants de microscopes proposent des formats de fichiers image propriétaires, les éditeurs de logiciels d’analyse d’images offrent des formats de fichiers personnalisés et partiellement ouverts. Il existe également des formats de fichiers traditionnels qui sont pris en charge par les bibliothèques Python courantes. Pour le stockage d’images à usage général, seuls très peu de formats de fichiers image tels que TIF peuvent être recommandés. De plus, les formats tels que JPEG devraient être évités pour préserver l’intégrité des données d’image. Dans ce notebook, nous allons tester certains formats de fichiers en réenregistrant une image de microscopie dans ces formats, en rechargeant l’image et en comparant les images avant et après l’enregistrement.

Voir aussi

from skimage.data import cells3d
from skimage.io import imread, imsave
import pyclesperanto_prototype as cle
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import os
import warnings

Comme image d’exemple, nous utilisons l’image exemple Cells 3D de scikit-image qui a été fournie par l’Allen Institute for Cell Science. C’est une image entière non signée de 16 bits. Dans la première tentative, nous choisirons seulement un seul canal et un seul plan.

original_image = cells3d()[30, 1]
cle.imshow(original_image, colorbar=True)
../_images/2fd4f3cb5d1db35ea587fe3a672439cf57b8bdd1642ce9c43f80e1bf1cfb17c2.png

Pourquoi le JPEG devrait être évité#

Le format de fichier JPEG est, du moins par défaut dans de nombreux programmes, un format de fichier avec perte. Cela signifie que des informations sont perdues lors de l’enregistrement de l’image.

imsave("temp.jpg", original_image)
Lossy conversion from uint16 to uint8. Losing 8 bits of resolution. Convert image to uint8 prior to saving to suppress this warning.

L’avertissement ci-dessus le confirme. De plus, lorsque nous rechargeons l’image, nous pouvons voir dans la barre de couleur que la plage d’intensité est maintenant différente.

jpg_image = imread("temp.jpg")

cle.imshow(jpg_image, colorbar=True)
../_images/c5432ef7b7511eb2722b8833f37ef829db454a67be29e67f421fb2d13b5be18e.png

De plus, si nous zoomons, nous pouvons voir deux types d’artefacts JPEG typiques.

  • L’image est débruitée.

  • Nous voyons des patchs, par exemple de 8x8 pixels, et des bandes allant dans différentes directions.

fix, axs = plt.subplots(1,2,figsize=(10,10))

cle.imshow(original_image[140:170, 0:30], plot=axs[0])
cle.imshow(jpg_image[140:170, 0:30], plot=axs[1])
../_images/3a0ebffa4b1ae47385b05995c077b42b82de69c1cb33e089e90544f911e08366.png

Pour étudier ces erreurs quantitativement et aussi pour tester plusieurs formats de fichiers, nous écrivons une courte fonction qui enregistre et recharge l’image et produit un tableau avec quelques mesures,

def resave_image_statistics(original_image):
    """Enregistre et recharge une image dans plusieurs formats et retourne un tableau avec des statistiques d'image."""

    # préparer le tableau
    stats = {
        "ending":[],
        "data_type":[],
        "shape":[],
        "size":[],
        "min":[],
        "max":[],
        "mean":[],
        "standard_deviation":[],
        "mean_squared_error":[],
    }
    
    # parcourir différentes extensions de fichiers
    endings = [None, "tif","png","mhd","mha","jpg","gif","bmp"]
    for ending in endings:
        try:
            if ending is None:
                # utiliser l'image originale comme premier test
                reloaded_image = original_image
                size = np.NaN
            else:
                # enregistrer et recharger l'image
                filename = "temp." + ending
                imsave(filename, original_image)

                reloaded_image = imread(filename)
                size = os.path.getsize(filename)
            
            # déterminer les statistiques
            stats["ending"].append(ending)
            stats["data_type"].append(reloaded_image.dtype)
            stats["shape"].append(reloaded_image.shape)
            stats["size"].append(size)
            stats["min"].append(np.min(reloaded_image))
            stats["max"].append(np.max(reloaded_image.astype(float)))
            stats["mean"].append(np.mean(reloaded_image))
            stats["standard_deviation"].append(np.std(reloaded_image))

            stats["mean_squared_error"].append(np.mean((original_image - reloaded_image)**2))

        except ValueError:
            # certains formats ne sont pas pris en charge
            warnings.warn("Format de fichier non pris en charge : " + ending)
            pass

    return pd.DataFrame(stats)

Ensuite, nous appliquons cette fonction à une tranche d’image 2D.

resave_image_statistics(cells3d()[30, 1])
Lossy conversion from uint16 to uint8. Losing 8 bits of resolution. Convert image to uint8 prior to saving to suppress this warning.
Lossy conversion from uint16 to uint8. Losing 8 bits of resolution. Convert image to uint8 prior to saving to suppress this warning.
Lossy conversion from uint16 to uint8. Losing 8 bits of resolution. Convert image to uint8 prior to saving to suppress this warning.
ending data_type shape size min max mean standard_deviation mean_squared_error
0 None uint16 (256, 256) NaN 1091 58327.0 9346.115417 6139.322637 0.000000
1 tif uint16 (256, 256) 131328.0 1091 58327.0 9346.115417 6139.322637 0.000000
2 png uint16 (256, 256) 107470.0 1091 58327.0 9346.115417 6139.322637 0.000000
3 mhd uint16 (256, 256) 281.0 1091 58327.0 9346.115417 6139.322637 0.000000
4 mha uint16 (256, 256) 131350.0 1091 58327.0 9346.115417 6139.322637 0.000000
5 jpg uint8 (256, 256) 9271.0 0 237.0 36.005875 23.824527 32596.059555
6 gif uint8 (256, 256) 58225.0 4 227.0 36.014725 23.978329 32236.271164
7 bmp uint8 (256, 256) 66614.0 4 227.0 36.014725 23.978329 32236.271164

Enregistrement d’images 3D#

Nous pouvons utiliser la même fonction pour tester quels formats de fichiers prennent en charge les images 3D.

resave_image_statistics(cells3d()[30])
File format not supported: png
File format not supported: mhd
File format not supported: mha
File format not supported: jpg
File format not supported: gif
File format not supported: bmp
ending data_type shape size min max mean standard_deviation mean_squared_error
0 None uint16 (2, 256, 256) NaN 277 58327.0 5925.968422 5711.584119 0.0
1 tif uint16 (2, 256, 256) 262566.0 277 58327.0 5925.968422 5711.584119 0.0

Enregistrement d’images 4D#

L’ensemble de données cells3d est en fait un ensemble de données 4D. Il contient également des canaux. Ainsi, nous pouvons l’utiliser pour tester également l’enregistrement et le rechargement de données 4D.

resave_image_statistics(cells3d())
File format not supported: png
File format not supported: mhd
File format not supported: mha
File format not supported: jpg
File format not supported: gif
File format not supported: bmp
ending data_type shape size min max mean standard_deviation mean_squared_error
0 None uint16 (60, 2, 256, 256) NaN 0 65535.0 4837.14054 3985.348828 0.0
1 tif uint16 (60, 2, 256, 256) 15748650.0 0 65535.0 4837.14054 3985.348828 0.0

Ainsi, le format de fichier TIF peut être recommandé. Il est également compatible avec une large gamme d’autres logiciels tels que ImageJ et Fiji.

Exercice#

Déterminez si les formats de fichiers ‘ico’ et ‘raw’ sont pris en charge.