El objetivo de esta actividad es demostrar como con técicas de Machine Learning podemos trabajar con imágenes y reducir el su tamaño gracias a métodos de aprendizaje no supervisado.
Para ello hemos usado el método de K-Means, un algoritmo de clasificación.
Algoritmo de K-Means
- Procedimiento
Simplemente reducimos el número total de colores utilizados para representar la imagen, y de esta forma permitimos que se necesiten menos memoria (bits) para su almacenaje.
Buscamos la similitud entre pixeles por medio de la creación de clusters, una vez que tengamos esa cercanía entre colores cambiaremos el color de todo ese cluster tomando como referencia el color del centroide.
Centroide: Pixel central del cluster.
Cargamos las librerias necesarias para la actividad
import cv2 import matplotlib.pyplot as plt import seaborn as sns from mpl_toolkits.mplot3d import Axes3D import numpy as np %matplotlib widget %matplotlib inline %matplotlib qt
Usamos una imagen para realizar la actividad. La imágen se otiene usando la libreria openCV
image = cv2.imread("images\meninas.jpg") cuadro=cv2.cvtColor(image, cv2.COLOR_BGR2RGB) ax = plt.axes(xticks=[], yticks=[]) ax.imshow(cuadro);
¿Cómo se representa una imágen?
Recordamos que las imagenes se representan como matrices de (alto, ancho, canales)
, donde los valores de los canales son rojo/verde/azul y varían de 0 a 255.
Sin embargo, podemos ver este dataset como una nube de puntos tridimensional, donde cada pixel es una instancia.
Vamos a normalizar los valores entre 0 y 1 y a convertirlos en [n_instancias, 3]
. Cada punto de 3 coordenadas se convierte en un valor.
#normalizamos la imagen para que tenga valores entre 0 y 1 data = cuadro / 255. data = data.reshape(cuadro.shape[0] * cuadro.shape[1], 3) data.shape
Representación de los pixeles de nuestra imágen en relación a su color
- Usamos cada canal como punto de representación
def plot_pixels(data, title, colors=None, N=10000): if colors is None: colors = datarng = np.random.RandomState(0) i = rng.permutation(data.shape[0])[:N] colors = colors[i] R, G, B = data[i].T
fig, ax = plt.subplots(1, 2, figsize=(14, 6))
ax[0].scatter(R, G, color=colors, marker='.') ax[0].set(xlabel='Red', ylabel='Green', xlim=(0, 1), ylim=(0, 1)) ax[0].set_title("Relación entre Rojo y Verde 2D") ax[1].scatter(R, B, color=colors, marker='.') ax[1].set(xlabel='Red', ylabel='Blue', xlim=(0, 1), ylim=(0, 1)) ax[1].set_title("Relación entre Rojo y Azul 2D")
fig.suptitle(title, size=20);
# plot
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(R, G, B, color=colors, marker='.') ax.set(xlabel='Red', ylabel='Green', zlabel="Blue") ax.set_title("Relación entre RGB 3D")
plt.show()
Usamos Machine Learning
Vamos ahora a reducir de 16 millones de colores a 16.
Como se trata de un dataset grande, vamos a usar una variación del k-means llamada mini-batch k-Means, que funciona exactamente igual que el k-means pero con mini-batches.
Lo que hacemos es utilizar como hiperparametro de KMeans el número de cluster igual 16, porque es el número de colores al cual queremos reducir. Esto significa que todos nuestros pixeles quedrán arupados en 16 grupos.
import warnings; warnings.simplefilter('ignore') # Fix NumPy issues. from sklearn.cluster import MiniBatchKMeans #Creamos la instancia del algortimo usando los hiperparametros kmeans = MiniBatchKMeans(n_clusters=16, random_state=42, batch_size=32) #Entrenamos kmeans.fit(data) #Obtenemos los colores que tienen los centroides new_colors = kmeans.cluster_centers_[kmeans.predict(data)] #Volvemos a visualizar las gráficas pero únicamente pasamos 16 colores de clasificación plot_pixels(data, colors=new_colors, title="Reducir espacio latente a 16 colores")
Como se puede observar se han reducido los colores a 16, ahora simplemente nos queda reconstruir la imágen y colocar cada pixel en su sitio.
Comprobamos el espacio que nos ocupa en memoria la nueva imágen.
Sin comprimir: 4320128
Comprimida: 128
Factor: 33751.0
Es indiscutible que se pierde calidad, pero pensad que acabamos de conseguir comprimir la imagen con un factor de 33751.0
Notebook completo
Referencias