Eigenfaces: reconstruye rostros con PCA

Resumen

Reconstruir un rostro humano usando solo una fracción de la información original es posible gracias a los eigenfaces, una aplicación directa de PCA que permite comprimir imágenes faciales conservando sus rasgos más distintivos. Esta técnica es la base del reconocimiento facial moderno y de la compresión de imágenes, y resulta clave para quienes trabajan con visión por computadora o aprendizaje automático.

¿Qué son los eigenfaces y por qué funcionan?

Cuando aplicas PCA a un conjunto de imágenes de rostros, los componentes principales que encuentra el algoritmo no son ejes abstractos: son literalmente caras fantasmas. El primer componente suele capturar la iluminación general, mientras que los siguientes describen rasgos como la forma de la nariz, la línea de la mandíbula o la posición de los ojos [00:24].

La idea central es que cualquier rostro puede representarse como una combinación ponderada de estas eigenfaces. Si usas solo las más relevantes, puedes reconstruir la imagen original con muchísima menos información.

¿Qué es una eigenface? Es un componente principal obtenido al aplicar PCA sobre un conjunto de imágenes de rostros. Cada eigenface representa un patrón de variación visual común entre todas las caras del dataset.

¿Cómo aplicar PCA al dataset de Olivetti Faces?

El dataset Olivetti Faces de scikit-learn contiene 400 imágenes de rostros humanos en escala de grises, cada una de 64 por 64 píxeles, lo que equivale a 4096 píxeles por imagen [02:08]. Esa es la dimensionalidad que vas a reducir.

Los pasos en Google Colab son directos:

  1. Importar fetch_olivetti_faces desde sklearn.datasets y cargar el dataset con shuffle=True para obtener imágenes aleatorias.
  2. Extraer la matriz X = faces_data.data, que tiene forma 400 por 4096.
  3. Guardar las dimensiones de cada imagen con H, W = faces_data.images.shape[1], faces_data.images.shape[2].
  4. Crear la instancia con pca = PCA(n_components=150) y entrenarla con pca.fit(X).

El método fit encuentra los 150 componentes principales sobre todo el conjunto de datos. Luego, con pca.transform(cara_original) aplicas esa transformación a una sola imagen [04:36]. Esa separación entre fit y transform es importante: no usas fit_transform porque ya tienes los componentes calculados y solo quieres proyectar una cara nueva.

¿Cómo reconstruir una imagen con menos componentes?

La parte más visual del proceso es comparar reconstrucciones con distinto número de componentes. Para eso, defines una función reconstruir_con_componentes(K) que toma los primeros K valores de la cara comprimida y rellena el resto con ceros usando np.zeros((1, 150 - K)) y np.c_[cara_reducida, padding] [06:12].

Después aplicas pca.inverse_transform(cara_reducida) para volver al espacio de píxeles originales y un reshape(H, W) para visualizar el resultado con imshow y cmap='gray'.

Los resultados visuales hablan por sí solos:

  • Con K = 10 la cara se reconoce, pero se pierden detalles como la barba, el bigote o los lentes.
  • Con K = 50 ya distingues bastantes rasgos, aunque la imagen sigue siendo borrosa.
  • Con K = 150 la reconstrucción se parece muchísimo a la original, usando apenas una fracción de los 4096 píxeles iniciales.
  • Con K = 300 prácticamente no notas diferencia con la imagen original [09:48].

¿Por qué se rellena con ceros al usar menos componentes? Porque inverse_transform espera un vector con la misma cantidad de componentes que se usaron en el fit. Rellenar con ceros equivale a anular la contribución de los componentes que no quieres considerar.

¿Qué tan eficiente es esta compresión?

Pasar de 4096 píxeles a 150 componentes representa una reducción cercana al 96% del tamaño original conservando una calidad visual notable. Esa eficiencia es la que hace de PCA una herramienta tan usada en compresión de imágenes y en sistemas de reconocimiento facial.

¿Qué errores comunes evitar al programar eigenfaces?

Durante la implementación es fácil cometer descuidos que rompen el flujo. Dos para tener presentes:

  • Confundir un punto con una coma al concatenar matrices con np.c_, lo que provoca un AttributeError sobre el padding.
  • Olvidar actualizar el parámetro n_components cuando cambias el número objetivo, por ejemplo al pasar de 150 a 300 sin reentrenar el modelo.

Reentrenar el PCA con el nuevo valor y volver a ejecutar el transform resuelve ambos casos.

¿Cómo practicar con tus propios datos?

Un buen ejercicio es tomar un dataset distinto: rostros de tus amigos, de tu familia o cualquier conjunto público de caras. Aplica el mismo flujo y observa qué detalles se pierden con 10, 50 o 100 componentes, y si 150 son suficientes para tu caso. Comparte tus hallazgos en los comentarios.

¿Cuál fue el componente mínimo con el que aún reconociste la cara? Cuéntalo abajo.