Ventajas y desventajas de los formatos de archivo de imagen#

Cuando se trabaja con datos de imágenes de microscopía, circulan muchos formatos de archivo. La mayoría de los proveedores de microscopios traen formatos de archivo de imagen propietarios, los proveedores de software de análisis de imágenes ofrecen formatos de archivo personalizados y parcialmente abiertos. También existen formatos de archivo tradicionales que son compatibles con bibliotecas comunes de Python. Para el almacenamiento de imágenes de propósito general, solo se pueden recomendar muy pocos formatos de archivo de imagen, como TIF. Además, se deben evitar formatos como JPEG para conservar la integridad de los datos de la imagen. En este cuaderno, probaremos algunos formatos de archivo guardando una imagen de microscopía en estos formatos, recargando la imagen y comparando las imágenes antes y después de guardar.

Ver también

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

Como imagen de ejemplo, usamos la imagen de ejemplo Cells 3D de scikit-image que fue proporcionada por el Instituto Allen para la Ciencia Celular. Es una imagen de enteros sin signo de 16 bits. En el primer intento, elegiremos solo un canal y un plano.

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

Por qué se debe evitar JPEG#

El formato de archivo JPEG es, al menos por defecto en muchos programas, un formato de archivo con pérdidas. Eso significa que se pierde información al guardar la imagen.

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.

La advertencia anterior lo confirma. Además, cuando recargamos la imagen, podemos ver en la barra de colores que el rango de intensidad es diferente ahora.

jpg_image = imread("temp.jpg")

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

Además, si hacemos zoom, podemos ver dos tipos de artefactos típicos de JPEG.

  • La imagen está desruidada.

  • Vemos parches, por ejemplo, de 8x8 píxeles y franjas que van en diferentes direcciones.

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

Para investigar esos errores cuantitativamente y también para probar múltiples formatos de archivo, escribimos una función corta que guarda y recarga la imagen y genera una tabla con algunas mediciones,

def resave_image_statistics(original_image):
    """Guarda y recarga una imagen en múltiples formatos y devuelve una tabla con estadísticas de imagen."""

    # preparar tabla
    stats = {
        "ending":[],
        "data_type":[],
        "shape":[],
        "size":[],
        "min":[],
        "max":[],
        "mean":[],
        "standard_deviation":[],
        "mean_squared_error":[],
    }
    
    # recorrer diferentes extensiones de archivo
    endings = [None, "tif","png","mhd","mha","jpg","gif","bmp"]
    for ending in endings:
        try:
            if ending is None:
                # usar la imagen original como primera prueba
                reloaded_image = original_image
                size = np.NaN
            else:
                # guardar y recargar imagen
                filename = "temp." + ending
                imsave(filename, original_image)

                reloaded_image = imread(filename)
                size = os.path.getsize(filename)
            
            # determinar estadísticas
            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:
            # algunos formatos no son compatibles
            warnings.warn("Formato de archivo no compatible: " + ending)
            pass

    return pd.DataFrame(stats)

A continuación, aplicamos esa función a un corte de imagen 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

Guardando imágenes 3D#

Podemos usar la misma función para probar qué formatos de archivo admiten imágenes 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

Guardando imágenes 4D#

El conjunto de datos cells3d es en realidad un conjunto de datos 4D. También contiene canales. Por lo tanto, podemos usarlo para probar el guardado y recarga de datos 4D también.

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

Por lo tanto, se puede recomendar el formato de archivo TIF. También es compatible con una amplia gama de otros software como ImageJ y Fiji.

Ejercicio#

Determina si los formatos de archivo ‘ico’ y ‘raw’ son compatibles.