Análisis de Componentes Principales en Imágenes: Reducción Dimensional
Resumen
¿Qué es el análisis de componentes principales?
El análisis de componentes principales (PCA, por sus siglas en inglés) es una técnica invaluable en el mundo del procesamiento de datos para reducir la cantidad de dimensiones con las que trabajamos. Frecuentemente, enfrentamos conjuntos de datos con muchas variables, y PCA nos ayuda a conservar el 80% de la información más relevante con menos variables. En síntesis, simplifica nuestros datos sin perder demasiada información esencial.
¿Cómo preparar datos de imágenes para PCA?
Para ilustrar cómo aplicar PCA, veamos un ejemplo con imágenes. Utilizaremos un conjunto de datos de rostros del laboratorio Olivetti, creado entre 1992 y 1994 en los laboratorios de Cambridge.
Paso 1: Importar librerías necesarias
Utilizaremos librerías de Python como numpy, matplotlib, y pandas para realizar las operaciones requeridas:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
Paso 2: Leer y normalizar las imágenes
Primero, cargamos las imágenes desde un directorio específico. Luego, normalizamos los valores de las imágenes dividiéndolos por 255, el valor máximo posible en una imagen en escala de grises.
image = np.random.rand(112,92)# ejemplo de una imagenimage_normalizada = image /255.0
Paso 3: Visualización sin ejes
Para graficar estas imágenes sin mostrar los ejes cartesianos, los configuramos así:
Configuramos un DataFrame para conservar los datos de cada imagen a medida que las leemos. Esto requiere recorrer los archivos de imágenes disponibles.
from glob import glob
imagenes = glob('imagenes/*')caras = pd.DataFrame()for archivo in imagenes: img = plt.imread(archivo).flatten()# aplanar la imagen caras = caras.append([img], ignore_index=True)
Paso 2: Visualización de un subconjunto de imágenes
Podemos mostrar un conjunto de imágenes seleccionando un número de individuos y el número de tomas para cada uno:
fig, axs = plt.subplots(5,10, figsize=(15,8))for i, ax inenumerate(axs.flatten()): img = caras.iloc[i].values.reshape(112,92)# reconstruir la forma original ax.imshow(img, cmap='gray') ax.set_xticks([]) ax.set_yticks([])plt.subplots_adjust(wspace=0.1, hspace=0.01)plt.show()
Este setup nos permite tener una vista preliminar del conjunto de datos con el que trabajaremos en PCA.
Reflexiones finales
El análisis de componentes principales se convertirá en un aliado fundamental para el análisis y procesamiento de datos, especialmente cuando se trabaja con imágenes o datasets de alta dimensionalidad. Además, el uso correcto de librerías como numpy y pandas optimiza la preparación y limpieza de datos. ¡Vamos a seguir explorando el potencial de estas herramientas y a comprender a fondo sus aplicaciones!
Alli se descarga automaticamente como dice johanR todo el dataset en la variable data
tampoco es necesario normalizar los valores porque ya en el dataset estan normalizados, lo unico que se necesitaria es consumirlos.
la variable data contiene el dataset, pero los valores estarian dentro de data.data.
Ademas, data.data es un array almacena individualmente cada imagen en cada posicion del mismo.
La imagen esta almacenada como una tira de valores (todos los valores en una sola dimension), como necesitamos es una matriz, le aplicaremos un reshape.
Las imagenes tienen 4096 valores en una dimension, el cual es un tamaño de 64 x 64 en dos dimensiones, entonces por ejemplo hariamos algo asi:
En la siguiente clase en el sistema de archivos se puede acceder a las imágenes y a todos los archivos del curso. La carpeta que utiliza se encuentra en la sección de PCA, llamada "imagenes". Sólo es necesario descargar esa carpeta.
Gracias.
PCA es una técnica muy útil para reducir la cantidad de dimensiones con las que estamos trabajando.
Muchas veces nuestro conjunto de datos es muy grande y es necesario reducirlo al menos en un 20%, dejando el 80% de datos mas significativo.
Un pequeño aporte de mi parte:
Muchos se daran cuenta que al correr el codigo
from glob import iglob
caras = pd.DataFrame([])for path iniglob(".\\imagenes\\*\\*.pgm"): im = imageio.imread(path) cara = pd.Series(im.flatten(), name = path) caras = caras.append(cara)
Les generará intriga el mensaje de advertencia en la consola:
<ipython-input-10-ec2cdce44f6c>:7: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
caras = caras.append(cara)
Este mensaje es basicamente que usar frame.append() va a quedar obsoleto en un futuro, por lo que usar pandas.concat se ve como una solución atractiva al mensaje de advertencia, sin embargo rapidamente nos damos cuenta que pandas.concat nos genera un resultado distinto a frame.append() por lo que el codigo deja de funcionar.
Les comparto mi solución sencilla a lo anterior.
from glob import iglob
caras = pd.DataFrame([])for path iniglob(".\\imagenes\\*\\*.pgm"): im = imageio.imread(path) cara = pd.Series(im.flatten(), name = path) caras = pd.concat([caras, cara], axis=1)caras = caras.T
Espero les sirva!
Gracias amigo, estaba teniendo problemas con eso.
Muchas gracias amigo, justo estaba atascado en lo mismo.
Aunque si bien puede ser más fácil descargar las imágenes de la libreria de sklearn, con este código aprendemos a cargar nuestros propios datasets de imágenes, vale la pena entenderlo.
Para los que esten usando google colab y no quieran complicarse descargando las imagenes, el codigo quedaria así:
Si estan utilizando el caras.append() deben eliminar el caras.T y listo
Muchas gracias por tu solucion tuve muchos problemas con la clase del profe que se demoraba mucho y el tamaño de las imagenes no las leia. Este resulto mas sencillo.
“imageio” ya esta obsoleta. En lugar de eso se puede usar:
import imageio.v2as imageio
o
import imageio.v3as iio
Para no ver los ejes cartesianos pueden usar tambien esto:
ax.set_axis_off()
tendria que ser:
ax[0].axis('off')
ax[1].axis('off')
basicamente remover individualmente el axis de cada subplot, tambien usando un ciclo
Para los que no saben usar el dataset de scikit learn que compartio johanR, con ese dataset no hay necesidad de usar imageio para cargar las imagenes, porque ya al hacer:
Alli se descarga automaticamente, como dice johanR, todo el dataset en la variable data
tampoco es necesario normalizar los valores porque ya en el dataset estan normalizados, lo unico que se necesitaria es consumirlos.
la variable data contiene el dataset, pero los valores estarian dentro de data.data.
Ademas, data.data es un array almacena individualmente cada imagen en cada posicion del mismo.
La imagen esta almacenada como una tira de valores (todos los valores en una sola dimension), como necesitamos es una matriz, le aplicaremos un reshape.
Las imagenes tienen 4096 valores en una dimension, el cual es un tamaño de 64 x 64 en dos dimensiones, entonces por ejemplo hariamos algo asi:
En el minuto 10:05, para saber las dimensiones a las que se debe volver a dar forma basta con ejecutar:
im.shape
Por qué especifica que el tipo de dato debería ser "np.uint8"?
Hola, todo parte de que una computadora solo lee 0 y 1, algo que seguro sabes.Cuando hablamos de un bit las unicas opciones son o un cero o un uno,es decir dos posibilidades, si tenemos dos bits tendriamos 10,01,00 y 11, es decir 4 (2^2) posibilidades.Cuando hablamos de 8 bits tenemos en total 256 (2^8) posibilidades, ahora al hacer np.uint8 le estamos diciendo a numpy que nuestros datos seran de 8 bits y esto es porque al trabajar con una imagen en escala de grises, la intensidad de cada pixel tiene un valor numerico entre 0 y 255,es decir 256 posibilidades.
Como dato el 0 es negro y el 255 blanco.
Todo está mas claro ahora, muchísimas gracias!
Para los que están en colab y tiene lios para montar las imagenes
caras = pd.DataFrame([])for root, dirs, files in os.walk(path):for file infiles: im = imageio.imread(root+"/"+file)/255 cara = pd.Series(im.flatten(), name=path) caras = caras.append(cara)fig, axes = plt.subplots(5,10, figsize=(15,8), subplot_kw ={'xticks':[],'yticks':[]}, gridspec_kw =dict(hspace =0.01, wspace =0.01))for i, ax inenumerate(axes.flat): ax.imshow(caras.iloc[i].values.reshape(112,92), cmap ="gray")
Para poder abrir la imagen en google colab yo usé las siguientes líneas de código, además de subir la carpeta a mi drive
<code>from google.colabimport drive
drive.mount('/content/drive')%cd "/content/drive/MyDrive/Colab Notebooks/Curso AL aplicada a machine learning/Img/imagenes/s3"im = imageio.imread("./3.pgm")
Cuando preparamos datos para PCA, es crucial que estén normalizados a un rango como [0,1] o [-1,1]. Esto se debe a que PCA busca las direcciones de máxima varianza en los datos, y si las características tienen diferentes escalas, algunas pueden dominar el análisis, distorsionando los resultados. Al estandarizar, aseguramos que todas las características contribuyan equitativamente, facilitando la identificación de patrones y la reducción dimensional de manera efectiva.
from sklearn.datasetsimport fetch_olivetti_faces
data =fetch_olivetti_faces()caras =[]for index inrange(50): cara = pd.Series(data.data[index].reshape(64,64).flatten(), name = index) caras.append(cara)fig, axes = plt.subplots(5,10, figsize=(15,8), subplot_kw={'xticks':[],'yticks':[]}, gridspec_kw=dict(hspace=0.01, wspace =0.01))caras = pd.DataFrame(caras)for i, ax inenumerate(axes.flat): ax.imshow(caras.iloc[i].values.reshape(64,64), cmap ='gray')
El PCA en imágenes es una técnica poderosa para reducir el tamaño y la complejidad de una imagen sin perder (demasiada) información relevante. En lugar de operar sobre datos tabulares, se aplica sobre los pixeles de la imagen, que pueden tratarse como vectores de alta dimensión.
📌 ¿Por qué aplicar PCA a imágenes?
🔻 Reducción de tamaño (compresión).
🔍 Eliminación de ruido.
⚡ Aceleración de modelos de visión por computador.
🎨 Reconstrucción visual con menos información.
🖼️ ¿Cómo se aplica?
Una imagen a color (RGB) es una matriz 3D: alto × ancho × 3 canales. Se puede aplicar PCA por canal o convertirla a escala de grises y luego aplicar PCA sobre la matriz 2D resultante.
🧪 Ejemplo Práctico: PCA aplicado a una imagen con Python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from skimage.color import rgb2gray
from skimage.io import imread
# 1. Cargar imagen y convertir a escala de grises
img = imread('tu_imagen.jpg') # Reemplaza con una ruta válida
gray_img = rgb2gray(img)
# 2. Visualizar la imagen original
plt.imshow(gray_img, cmap='gray')
plt.title("Imagen Original")
plt.axis("off")
plt.show()