Python: medidas e histogramas#

Aquí, exploraremos cómo realizar mediciones y generar histogramas con Python.

# Our usual default imports
import sys
sys.path.append('../../../')

from helpers import *
import matplotlib.pyplot as plt

# Read an image - we need to know the full path to wherever it is
im = load_image('happy_cell.tif')

# Show the image
plt.imshow(im, cmap='gray')
plt.show()
../../../_images/161d80c4c99ec54406aa1da1413c5c9b995d2626af9d083e94c06c7ed990ef27.png

Introducción a las matrices NumPy#

Las imágenes con las que estamos trabajando en Python son NumPy arrays o matrices NumPy - https://numpy.org

En lugar de trazar la imagen con plt.imshow, también podemos simplemente imprimir sus valores. Dado que puede haber muchos valores (es decir, millones de píxeles por imagen), solo se muestran unos pocos de forma predeterminada.

print(im)
[[2. 2. 2. ... 2. 2. 2.]
 [2. 2. 2. ... 2. 2. 2.]
 [2. 2. 2. ... 2. 2. 2.]
 ...
 [2. 2. 2. ... 2. 2. 2.]
 [2. 2. 2. ... 2. 2. 2.]
 [2. 2. 2. ... 2. 2. 2.]]

Si queremos saber cuántos valores hay en una imagen, podemos consultar su «forma».

Esto nos da el tamaño en el orden «(alto, ancho)».

print(im.shape)
(240, 250)

Siempre que tengamos una matriz NumPy 2D, podemos transponerla fácilmente, lo que cambiará los valores de ancho y alto.

im2 = im.transpose()
print(im2.shape)
plt.imshow(im2)
plt.show()
(250, 240)
../../../_images/1596a475c10e7f7c87130a98ecaeebfebb5eaa4f3db9c9004ebf3a4b89007103.png

Calcular estadísticas#

Un beneficio más significativo de trabajar con matrices NumPy, al menos para nuestros propósitos, es que nos permiten calcular algunas estadísticas resumidas de forma extremadamente fácilmente.

Por ejemplo, para calcular el valor promedio (medio) de píxel, simplemente podemos usar im.mean().

im.mean()
23.031446

Si eso es lo último que agregamos a una celda de código, entonces el resultado se mostrará en nuestro cuaderno.

Sin embargo, si queremos imprimir múltiples valores -y múltiples estadísticas- en rápida sucesión, debemos usar la función «imprimir» nuevamente.

print(im.mean())
print(im.min())
print(im.max())
print(im.std())
23.031446
2.0
65.75
27.156355

Formatear el output#

Las cosas se vuelven más legibles si agregamos texto adicional, en lugar de simplemente imprimir números.

Una de las formas más sencillas de hacer esto es utilizar una “cadena f”, que tiene el formato f'algun texto {alguna_variable}.

La parte entre llaves {} puede ser un cálculo, y si agrega :.2f al final, esto limitará opcionalmente el número de decimales (aquí, a dos).

print(f'Mean:     {im.mean()}')
print(f'Minimum:  {im.min():.1f}')
print(f'Maximum:  {im.max():.2f}')
print(f'Std.dev.: {im.std():.3f}')
Mean:     23.03144645690918
Minimum:  2.0
Maximum:  65.75
Std.dev.: 27.156

Generando histogramas#

Ahora podemos intentar generar histogramas de imágenes usando plt.hist.

Es posible que esperes que plt.hist(im) funcione, tal como lo hizo anteriormente plt.imshow(im). Sin embargo, el resultado puede parecer un poco sorprendente.

plt.hist(im)
plt.show()
../../../_images/0f7e50b118b7808334b5311116fe660a6c0201c1ee0d726a96f62e13022dd233.png

El problema es que la imagen es 2D y plt.hist espera solo una lista de valores 1D. Podemos generar eso con una llamada a .flatten() y usar la matriz aplanada para crear el histograma.

print(f'Shape before flatten(): {im.shape}')
im_flat = im.flatten()
print(f'Shape after flatten(): {im_flat.shape}')
Shape before flatten(): (240, 250)
Shape after flatten(): (60000,)
plt.hist(im_flat)
plt.show()
../../../_images/5a3124e702bade2480a07990c79e06028b9cd84297ef294d291148f182f5eac0.png

Al igual que con plt.imshow, tenemos muchas opciones para personalizar el histograma. Esto incluye la capacidad de establecer el color o la cantidad de contenedores de histograma.

plt.hist(im.flatten(), bins=50, color='red')
plt.show()
../../../_images/1bcf3a40da0b295cc9cda2be837786804054327681f82769ea0283f24fc6de9e.png

Paréntesis

Inicialmente puede resultar confuso por qué a veces necesitamos paréntesis () y otras no, p.e. im.flatten() frente a im.shape.

Como regla general, los paréntesis indican que estamos llamando a un método que hace algo (por ejemplo, imprime un valor, calcula un promedio, aplana una matriz).

Cuando no vemos paréntesis, esto indica que estamos accediendo a un campo o propiedad (por ejemplo, la forma de una matriz).

En la práctica, la distinción a veces puede resultar un poco confusa a medida que se profundiza en Python, pero sirve como guía general.