ImageJ: tipos y profundidades de bits#

Hide code cell content
%load_ext autoreload
%autoreload 2

# Default imports
import sys
sys.path.append('../../../')
from helpers import *
from matplotlib import pyplot as plt
from myst_nb import glue
import numpy as np
from scipy import ndimage

Introducción#

La profundidad de bits y el tipo de una imagen se determinan antes de abrirla en ImageJ. Si los datos se recortan, ya son incorrectos antes de comenzar, y ninguna cantidad de magia de ImageJ recuperará la información.

Aquí exploraremos cómo:

  • Verifique la profundidad de bits y el tipo

  • Diagnostica cuándo puede haber ocurrido un recorte

  • Convierte la profundidad y la altura de bits (con cuidado) si es necesario

Comprobación de la profundidad de bits y el tipo#

La profundidad de bits y el tipo están relacionados entre sí: ambos son necesarios para convertir datos binarios en valores de píxeles. ImageJ no siempre hace una distinción cuidadosa entre los dos.

La lista completa de tipos de imágenes admitidos por ImageJ se encuentra en el submenú Image ‣ Type ‣ . Las tres primeras entradas son las más importantes; estas son

  • 8 bits – entero sin signo

  • 16 bits: entero sin signo

  • 32 bits – punto flotante

Aunque parecen profundidades de bits, se enumeran como «tipos». Pero dado que las imágenes de 8 y 16 bits en ImageJ son siempre enteros sin signo, y las imágenes de 32 bits son siempre de punto flotante, no hay ambigüedad.

Puedes ver el tipo de imagen actual comprobando qué elemento en Image ‣ Type ‣ tiene una marca de verificación al lado. Pero normalmente no es necesario; También puedes ver la información en la parte superior de la ventana de la imagen.

Hide code cell content
fig = create_figure(figsize=(8, 4))
show_image('images/type-window-series.png', pos=121)
show_image('images/type-window-neuron.png', pos=122)
glue_fig('fig_types_windows', fig)
../../../_images/15b0f93830d4b4bc9209aa7063c96f3bf9ffc517fb03f71b3218abd3e3c393e1.png

Figura 24 El texto en la parte superior de cada ventana de imagen proporciona información útil. Aquí, la imagen de la izquierda es de 8 bits y la imagen de la derecha es de 16 bits.#

Hay varios otros tipos enumerados en Image ‣ Type ‣, todos los cuales tienen una asociación con el color. Son menos diferentes de lo que parecen a primera vista: una imagen RGB es en realidad una imagen de 8 bits con tres canales (correspondientes a rojo, verde y azul). Exploraremos esto en Canales y colores.

Diagnóstico de problemas#

El mayor problema asociado con la profundidad de bits y el tipo de una imagen es el recorte. Analyze ‣ Histogram es el comando esencial necesario para diagnosticar si algo anda mal; simplemente presiona H para ejecutarlo.

Hide code cell content
fig = create_figure(figsize=(8, 4))
show_image('images/imagej-histogram-unclipped.png', title="Good image (no clipping)", pos=121)
show_image('images/imagej-histogram-clipped.png', title="Clipped image", pos=122)
glue_fig('fig_types_imagej_clipping', fig)
../../../_images/c933a5131274976c9d37f99f5d07dcca3c89b1863298fa7737c337a5521ac4a8.png

Figura 25 Dos imágenes de apariencia similar y sus histogramas: una recortada, la otra no.#

La señal principal de que una imagen fue recortada es un gran pico en cada extremo del histograma. Esto puede requerir una inspección cuidadosa para distinguirlo del borde negro que rodea el histograma en ImageJ.

Si conoces la profundidad de bits y el tipo de imagen, puedes calcular el rango (por ejemplo, 0-255 para una imagen entera sin signo de 8 bits, 0-65,535 para 16 bits) y, por lo general, eso da una buena indicación de dónde los picos estarían, pero no es una guía perfecta. Posiblemente, podríamos tener una imagen recortada con algún otro valor porque se le ha re-escalado después del recorte.

¿La siguiente imagen muestra signos de haber sido recortada?

../../../_images/imagej-histogram-maybe.png

¡Sí! Hay un pequeño pico en el extremo superior del histograma, correspondiente a valores de píxeles de 4095. Este es en sí mismo un número sospechoso porque sería el valor máximo posible en una imagen entera sin signo de 12 bits (es decir, 212 - 1) - así que supongo que esa fue la profundidad de bits del dispositivo de adquisición.

Es cierto que la imagen no está muy mal recortada. Podríamos comprobar la proporción de píxeles con ese valor y utilizarlo para estimar si es probable que el recorte tenga un impacto significativo en un análisis posterior. Pero es mejor evitar el recorte por completo cuando sea posible.

Convertir imágenes#

Hay tres escenarios principales en los que es posible que necesites convertir el tipo o la profundidad de bits de una imagen:

  • Reducir el tamaño del archivo

  • Conversión a 8 bits para mostrar la imagen en otro software

    • Porque las imágenes de 8 bits son más comunes fuera de la ciencia

  • Conversión a punto flotante antes de realizar operaciones de procesamiento de imágenes

    • Porque (como veremos más adelante en el libro) estos a menudo requieren fracciones y números negativos.

Ten en cuenta que revertir los efectos del recorte no está en la lista: si una imagen se recorta durante la adquisición, cualquier conversión posterior no ayudará. Los datos recortados desaparecieron para siempre.

Sin embargo, aún se puede introducir recorte después de la adquisición al realizar conversiones desacertadas, con todas las desafortunadas consecuencias que esto conlleva. Por lo tanto, es importante saber cómo funciona la conversión de tipos de ImageJ.

Aumentar la profundidad de bits#

Comencemos con el caso fácil: aumentar la profundidad de bits de una imagen.

En principio, podemos convertir una imagen simplemente eligiendo el tipo que queremos en el submenú Image ‣ Type ‣.

En ImageJ, en realidad sólo hay tres profundidades de bits y tipos asociados. Esto significa que las únicas conversiones que pueden aumentar la profundidad de bits son:

  • 8 bits (entero sin signo) → 16 bits (entero sin signo)

  • 8 bits (entero sin signo) → 32 bits (punto flotante)

  • 16 bits (entero sin signo) → 32 bits (punto flotante)

Afortunadamente,

  • cualquier valor entero sin signo de 8 bits se puede representar en una imagen de entero sin signo de 16 bits

  • cualquier valor entero sin signo de 16 bits se puede representar en una imagen de punto flotante sin signo de 32 bits

En consecuencia, aumentar la profundidad de bits debería ser siempre seguro. Sin embargo…

¡Prepárate siempre para que el software nos sorprenda!

No debemos ser complacientes con las conversiones de imágenes, incluso si pensamos que deberían estar bien. Es muy fácil medir imágenes (presiona M) que siempre debemos verificar antes y después de la conversión para asegurarnos de que las medidas resumidas no hayan cambiado.

Reducir la profundidad de bits#

Reducir la profundidad de bits es donde acechan los mayores peligros. Entonces no todos los valores de una imagen con una profundidad de bits más alta encajan en una imagen con una profundidad de bits más baja.

El proceso es el mismo: elige el tipo que desees en el submenú Image ‣ Type ‣.

Pero lo que sucede a continuación depende de si la opción Scale When Converting en Edit ‣ Options ‣ Conversions… está marcado o no.

  • Scale When Converting no está marcada: a los píxeles simplemente se les da el valor válido más cercano dentro de la nueva profundidad de bits, es decir, hay recorte y redondeo según sea necesario.

    • Ejemplo: si convierte una imagen a 8 bits, no se perderán datos solo si cada valor de píxel antes de la conversión es un número entero en el rango de 0 a 255. Cualquier otro valor se redondeará o recortará.

  • Scale When Convertingis checked: se suma o resta una constante, luego los píxeles se dividen entre otra constante antes de asignarlos al valor válido más cercano dentro de la nueva profundidad de bits. Sólo entonces se aplica el recorte o el redondeo si aún es necesario.

Scale When Converting está activado de forma predeterminada y, como lo sugiere Figura 22, suele ser el mejor opción. La pregunta entonces es de dónde vienen las constantes para realizar el re-escalado.

Quizás sea sorprendente que se determinen a partir del Mínimum y Maximum en la configuración Brillo/Contraste actual. .: se resta el Mínimo y el resultado se divide entre Máximo - Mínimo. Cualquier valor de píxel que sea inferior al Mínimo o superior al Máximo acaba siendo recortado. En consecuencia, convertir a una profundidad de bits más baja con escalado puede generar resultados diferentes dependiendo de cuáles fueron las configuraciones de brillo y contraste.

Esto significa que, idealmente, usaríamos un valor mínimo que sea igual al valor mínimo de píxel en la imagen y un valor máximo igual al valor máximo de píxel. Afortunadamente, existe una manera sencilla de lograrlo:

Restablece el rango de Brillo/Contraste antes de reducir la profundidad de bits

Si realmente necesitas reducir la profundidad de bits de una imagen en ImageJ, normalmente debes abrir Image ‣ Adjust ‣ Brightness/Contrast. .. (Shift+C) y presiona el botón Reset primero, para minimizar la pérdida de datos al recorte o al redondeo.

¿Por qué el escalado suele ser bueno al reducir la profundidad de bits y por qué generalmente se resta una constante antes de aplicar este escalado?

Sugerencia: Como ejemplo, considera cómo una imagen de 16 bits que contiene valores en el rango de 4000 a 5000 podría convertirse a 8 bits primero sin escalar y luego, alternativamente, escalar con o sin la resta constante inicial. ¿Qué constantes para la resta y la división normalmente minimizarían la cantidad de información perdida al convertir a una imagen de 8 bits, limitando los errores al redondeo únicamente y no al recorte?

En el ejemplo dado, la conversión a 8 bits sin ningún escalado daría como resultado que todos los píxeles simplemente pasaran a ser 255: se perdería toda la información útil de la imagen.

Con escala pero sin resta, tendría sentido dividir todos los valores de píxeles por el máximo de la imagen dividido por el máximo de la nueva profundidad de bits, es decir, por 5000/255. Esto conduciría a una imagen en la que los píxeles se encuentran en el rango de 204 a 255. Claramente se ha perdido mucha información: 1000 valores potencialmente diferentes ahora se han comprimido en 52.

Sin embargo, si primero restamos el más pequeño de nuestros valores de 16 bits (es decir, 4000), nuestro rango inicial pasa a ser 0-1000. Luego divide por 1000/255 y los nuevos valores se escalarán en todo el rango de una imagen de 8 bits, es decir, 0–255. Todavía hemos perdido información, pero considerablemente menos que si no hubiéramos restado primero la constante.

Asegúrate de que la opción Scale When Converting esté activada (debería estar activada de forma predeterminada). Luego, utilizando una imagen de muestra de 8 bits adecuada, p. File ‣ Open Samples ‣ Boats, explora los efectos de las configuraciones de brillo/contraste al aumentar o disminuir la profundidad de bits.

¿Puedes destruir la imagen simplemente 1) aumentando la profundidad de bits y luego 2) disminuyendo la profundidad de bits a su valor original?

lanzar ImageJ.JS

Generalmente es una buena idea elegir Reset en la ventana Brightness/Contrast… antes de reducir cualquier profundidades de bits para imágenes 2D (consulta Procesamiento multidimensional para leer sobre consideraciones especiales relacionadas con z-stacks o series de tiempo).

Puedes destruir una imagen aumentando su profundidad de bits, ajustando el brillo/contraste y luego disminuyendo la profundidad de bits al original nuevamente. Esto puede parecer extraño, porque claramente la profundidad de bits final es capaz de almacenar todos los valores de píxeles originales. Pero ImageJ no lo sabe y no lo comprueba, por lo que simplemente realizará su conversión normal de reducción de profundidad de bits basándose en la configuración de contraste.