Computación con imágenes#

Hemos visto en el último capítulo que las imágenes existen en forma de arrays de Numpy. Aquí veremos diferentes tipos de cálculos de procesamiento de imágenes que podemos hacer con dichos arrays, como operaciones aritméticas, combinación de imágenes, etc.

Hemos visto en el último capítulo que podíamos crear imágenes usando, por ejemplo, la función np.random.random. Vamos a crear dos imágenes pequeñas:

import numpy as np
from matplotlib import pyplot as plt
image1 = np.ones((3,5))
image1
array([[1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.]])
image2 = np.random.random((3,5))
image2
array([[0.1389824 , 0.99979463, 0.82577042, 0.79474507, 0.23101268],
       [0.27034647, 0.01410389, 0.20435784, 0.0721552 , 0.61984191],
       [0.85459468, 0.58800162, 0.62462822, 0.01819988, 0.06607906]])

Cálculo simple#

Como repaso del último capítulo, hemos visto que podemos hacer aritmética con imágenes tal como lo haríamos con números simples:

image1_plus = image1 + 3
image1_plus
array([[4., 4., 4., 4., 4.],
       [4., 4., 4., 4., 4.],
       [4., 4., 4., 4., 4.]])

Esto es válido para todas las operaciones básicas como suma, multiplicación, etc. Incluso elevar a una potencia dada funciona:

image1_plus ** 2
array([[16., 16., 16., 16., 16.],
       [16., 16., 16., 16., 16.],
       [16., 16., 16., 16., 16.]])

Combinando imágenes#

Si las imágenes tienen el mismo tamaño, podemos tratarlas aquí de nuevo como números simples y hacer matemáticas con ellas: de nuevo suma, multiplicación, etc. Por ejemplo:

image1 + image2
array([[1.1389824 , 1.99979463, 1.82577042, 1.79474507, 1.23101268],
       [1.27034647, 1.01410389, 1.20435784, 1.0721552 , 1.61984191],
       [1.85459468, 1.58800162, 1.62462822, 1.01819988, 1.06607906]])

Funciones píxel por píxel#

Además de permitirnos crear varios tipos de arrays, Numpy también nos proporciona funciones que pueden operar en arrays. En muchos casos, la entrada es una imagen y la salida es una imagen del mismo tamaño donde se ha aplicado una función dada a cada píxel individual.

Por ejemplo, podríamos querer aplicar una función logarítmica a una imagen para reducir el rango de valores que pueden tomar los píxeles. Aquí usaríamos la función np.log:

np.log(image2)
array([[-1.97340794e+00, -2.05388747e-04, -1.91438488e-01,
        -2.29733884e-01, -1.46528267e+00],
       [-1.30805091e+00, -4.26130469e+00, -1.58788269e+00,
        -2.62893591e+00, -4.78290819e-01],
       [-1.57127986e-01, -5.31025584e-01, -4.70598659e-01,
        -4.00634024e+00, -2.71690330e+00]])

Como podemos ver, la imagen de entrada tenía 3 filas y 5 columnas y la imagen de salida tiene las mismas dimensiones. Puedes encontrar muchas funciones en Numpy que operan de esta manera, por ejemplo, para tomar una exponencial (np.exp()), para hacer trigonometría (np.cos(), np.sin()) etc.

Estadísticas de imagen#

Otro tipo de funciones toma una imagen como entrada pero devuelve una salida de un tamaño diferente al calcular una estadística sobre la imagen o partes de ella. Por ejemplo, podemos calcular el promedio de todos los valores de píxel de image2:

np.mean(image2)
0.4215075982440046

O podemos especificar que queremos calcular la media a lo largo de cierta dimensión de la imagen, en 2D a lo largo de columnas o filas. Recordemos cómo es image2:

image2
array([[0.1389824 , 0.99979463, 0.82577042, 0.79474507, 0.23101268],
       [0.27034647, 0.01410389, 0.20435784, 0.0721552 , 0.61984191],
       [0.85459468, 0.58800162, 0.62462822, 0.01819988, 0.06607906]])

Ahora tomamos el promedio sobre las columnas, lo que significa a lo largo del primer eje o axis=0:

np.mean(image2, axis=0)
array([0.42130785, 0.53396671, 0.55158549, 0.29503338, 0.30564455])

La misma lógica se aplica a todas las demás funciones estadísticas como tomar el mínimo (np.min()), el máximo (np.max()), la desviación estándar (np.std()), la mediana (np.median()) etc.

Ten en cuenta que la mayoría de estas funciones también se pueden llamar directamente en la variable del array de Numpy. Por ejemplo

np.std(image2)
0.3362691013424119

y

image2.std()
0.3362691013424119

son completamente equivalentes. En el último caso, usando la notación de punto, podrías escuchar que std() es un método de image2.

Finalmente, podríamos querer echar un vistazo a la distribución real de los valores de los píxeles. Para esto, echamos un vistazo al histograma de la imagen.

number_of_bins = 10
min_max = [0,1]
histogram,bins = np.histogram(image2.ravel(),number_of_bins,min_max)
plt.hist(image2.ravel(), number_of_bins, min_max)
plt.show()
../_images/f1096d40d837e3fb2566f9bf2ec79e1169ddc427af6ff8d26e10e49374e021af.png

Ejercicio#

Del módulo numpy.random, encuentra una función que genere ruido Poisson y crea una imagen de 4x9. Calcula su media y desviación estándar.