Abriendo archivos LIF#

Cuando se trabaja con datos de imágenes de microscopía, circulan muchos formatos de archivo, como el Formato de Imagen Leica (LIF). En este notebook, abriremos un archivo .lif usando la biblioteca readlif.

Nota: Se recomienda usar AICSImageIO para leer imágenes LIF como se muestra en este notebook.

La biblioteca readlif se puede instalar así desde la terminal:

pip install readlif

Después de instalarla, se puede importar.

from readlif.reader import LifFile

import os
import requests
from skimage.io import imshow
import numpy as np

Como conjunto de datos de ejemplo, utilizaremos una imagen compartida por Gregory Marquart y Harold Burgess bajo la licencia CC-BY 4.0. Primero necesitamos descargarla.

filename = "../../data/y293-Gal4_vmat-GFP-f01.lif"
url = 'https://zenodo.org/record/3382102/files/y293-Gal4_vmat-GFP-f01.lif?download=1'

if not os.path.isfile(filename):
    # solo descargamos el archivo si aún no lo tenemos
    response = requests.get(url)
    open(filename, "wb").write(response.content)

En este punto, el archivo debería estar en nuestra computadora y se puede abrir así.

file = LifFile(filename)
file
'LifFile object with 1 image'
lif_image = file.get_image(0)
lif_image
'LifImage object with dimensions: Dims(x=616, y=500, z=86, t=1, m=1)'

De la LifImage, podemos obtener fotogramas individuales como imágenes PIL.

pil_image = lif_image.get_frame(z=0)
type(pil_image)
PIL.Image.Image

Finalmente, estas imágenes PIL 2D se pueden convertir en matrices numpy. Lo que nos permite eventualmente echar un vistazo a la imagen.

np_image = np.array(pil_image)
np_image.shape
(500, 616)
imshow(np_image)
/opt/miniconda3/envs/devbio-napari-env/lib/python3.9/site-packages/skimage/io/_plugins/matplotlib_plugin.py:149: UserWarning: Low image data range; displaying image with stretched contrast.
  lo, hi, cmap = _get_display_range(image)
<matplotlib.image.AxesImage at 0x1378ab970>
../_images/ab37ca7586f86a75885f777809caa8739c896fa9783d806b7bbd61dea6380d1b.png

Para acceder a todos los píxeles en nuestra imagen 3D, primero debemos echar un vistazo a los metadatos del archivo.

lif_image.info
{'dims': Dims(x=616, y=500, z=86, t=1, m=1),
 'display_dims': (1, 2),
 'dims_n': {1: 616, 2: 500, 3: 86},
 'scale_n': {1: 2.1354804344851965,
  2: 2.135480168493237,
  3: 0.9929687300128537},
 'path': 'Experiment_002/',
 'name': 'Series011',
 'channels': 2,
 'scale': (2.1354804344851965, 2.135480168493237, 0.9929687300128537, None),
 'bit_depth': (12, 12),
 'mosaic_position': [],
 'channel_as_second_dim': False,
 'settings': {}}

Por ejemplo, podría ser útil más adelante conocer el tamaño del vóxel en orden z/y/x.

voxel_size = lif_image.info['scale'][2::-1]
voxel_size
(0.9929687300128537, 2.135480168493237, 2.1354804344851965)

También podemos leer cuántas secciones tiene la pila 3D.

num_slices = lif_image.info['dims'].z
num_slices
86

Esta información nos permite escribir una función de conveniencia que permite convertir la imagen LIF en una pila de imágenes numpy 3D.

def lif_to_numpy_stack(lif_image):
    num_slices = lif_image.info['dims'].z
    
    return np.asarray([np.array(lif_image.get_frame(z=z)) for z in range(num_slices)])
image_stack = lif_to_numpy_stack(lif_image)
image_stack.shape
(86, 500, 616)

Esta pila de imágenes puede usarse luego, por ejemplo, para visualizar una proyección de intensidad máxima a lo largo de Z.

imshow(np.max(image_stack, axis=0))
<matplotlib.image.AxesImage at 0x137a1c610>
../_images/bfb0e9bded30a8f74d350d0d5c781a3f8026ddfd97ac4ac93384fb99e3693681.png