tutoriales.com

Restauración y Coloreado Automático de Fotografías Antiguas con Redes Neuronales y OpenCV

Descubre cómo devolverle la vida a fotografías antiguas y en blanco y negro aplicando técnicas avanzadas de visión artificial, redes neuronales convolucionales y modelos preentrenados en Python.

Intermedio8 min de lectura11 views
Reportar error

La fotografía analógica ha capturado la memoria y la historia de la humanidad durante más de un siglo. Sin embargo, el paso del tiempo es implacable: las imágenes se desvanecen, acumulan rayones, manchas de humedad y pierden su vitalidad original. En este tutorial completo, exploraremos cómo la visión artificial y el Deep Learning nos permiten automatizar la restauración de daños físicos en las imágenes y aplicar un coloreado realista impulsado por inteligencia artificial. A lo largo de las siguientes secciones, abordaremos los fundamentos teóricos y prácticos necesarios para transformar fotografías históricas deterioradas en vibrantes recuerdos digitales a todo color.

📌 Introducción y Objetivos del Tutorial

El objetivo principal de este tutorial es construir un pipeline completo de procesamiento de imágenes utilizando OpenCV y redes neuronales en Python. No nos limitaremos a aplicar filtros simples; utilizaremos arquitecturas modernas para reparar automáticamente imperfecciones estructurales y estimar la distribución cromática plausible de una escena en escala de grises.

Al finalizar este tutorial, serás capaz de:

  • Comprender la anatomía del daño fotográfico digitalizado y cómo abordarlo algorítmicamente.
  • Implementar algoritmos de inpainting clásico y basado en deep learning para eliminar rayones y roturas.
  • Utilizar redes neuronales preentrenadas especializadas en la colorización automática de imágenes monocromáticas.
  • Optimizar y post-procesar los resultados para obtener una calidad visual profesional y realista.
📌 Nota: Este tutorial requiere conocimientos básicos de programación en Python y manejo de la biblioteca OpenCV. Asegúrate de tener un entorno configurado antes de comenzar.

🛠️ Configuración del Entorno de Desarrollo

Antes de escribir nuestro código de restauración, necesitamos preparar nuestro entorno virtual e instalar las dependencias necesarias. Utilizaremos bibliotecas estándar de la industria como NumPy, OpenCV y PyTorch (o modelos compatibles con DNN de OpenCV).

Instalación de Dependencias

Abramos nuestra terminal y ejecutemos los siguientes comandos para instalar los paquetes requeridos:

pip install numpy opencv-python opencv-contrib-python matplotlib torch torchvision

Verifiquemos que la instalación se haya realizado correctamente creando un script básico de prueba de versión:

import cv2
import numpy as np
import torch

print("Versión de OpenCV:", cv2.__version__)
print("Versión de PyTorch:", torch.__version__)
print("CUDA disponible:", torch.cuda.is_available())
💡 Consejo: Si dispones de una tarjeta gráfica NVIDIA compatible con CUDA, el proceso de inferencia de las redes neuronales será significativamente más rápido.

🧱 Fundamentos de la Restauración Digital de Imágenes

El proceso de restauración fotográfica se divide tradicionalmente en dos etapas fundamentales: la eliminación de defectos físicos (como rasgaduras, polvo y manchas) y la reconstrucción cromática. En el ámbito digital, el daño se manifiesta como alteraciones en los valores de los píxeles que difieren drásticamente del contexto circundante.

Imagen Antigua Dañada Detección de Daños y Máscara Inpainting (Reparación de rayones) Colorización Neuronal Post-procesamiento y Balance Imagen Restaurada Final

La siguiente tabla resume las principales técnicas utilizadas y sus aplicaciones:

TécnicaDescripciónVentajasLimitaciones
------------
Inpainting basado en Navier-StokesAlgoritmo basado en ecuaciones diferenciales parciales de fluidos.Muy rápido y eficiente para pequeños rasguños.No comprende semánticamente el contenido complejo.
Inpainting Fast Marching (FMM)Método rápido basado en la velocidad de propagación de ondas de los bordes.Ideal para áreas pequeñas y líneas delgadas.Puede difuminar texturas complejas si la máscara es muy grande.
------------
Redes Neuronales de Inpainting (DeepFill)Modelos generativos entrenados para rellenar grandes huecos con contenido coherente.Reconstruye rostros, ojos y texturas faltantes de forma realista.Requiere mayor potencia de cálculo (GPU).
Colorización basada en LAB (SIGGRAPH '16)Redes convolucionales que mapean espacios de color usando pistas o de forma automática.Resultados artísticos y fotorrealistas en milisegundos.Puede requerir ajuste manual de tonos en casos complejos.

✂️ Paso 1: Eliminación de Rayones y Daños Físicos (Inpainting)

El primer desafío al restaurar una foto antigua es eliminar las marcas físicas. Para ello, necesitamos crear una máscara que identifique exactamente dónde se encuentran los daños (rayones, polvo, manchas blancas).

Creación de la Máscara de Daños

Podemos combinar umbrales de color y operaciones morfológicas para detectar automáticamente las imperfecciones más claras u oscuras sobre la superficie de la emulsión fotográfica.

import cv2
import numpy as np

# Cargar la imagen dañada
imagen_path = "foto_antigua_dañada.jpg"
img = cv2.imread(imagen_path)

if img is None:
    raise FileNotFoundError("No se pudo cargar la imagen. Verifica la ruta.")

# Convertir a escala de grises
grayscale = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Aplicar un umbral para detectar rayas y puntos blancos muy brillantes
_, mask = cv2.threshold(grayscale, 240, 255, cv2.THRESH_BINARY)

# Dilatar la máscara ligeramente para cubrir los bordes del rayón
kernel = np.ones((3, 3), np.uint8)
mask_dilatada = cv2.dilate(mask, kernel, iterations=1)

print("Máscara de daños generada con éxito.")

Aplicación del Algoritmo de Inpainting

Una vez obtenida la máscara, utilizamos la función de inpainting de OpenCV para rellenar los huecos basándonos en los píxeles circundantes.

# Aplicar inpainting utilizando el método Fast Marching Method (FMM)
radio_inpaint = 3
img_restaurada = cv2.inpaint(img, mask_dilatada, inpaintRadius=radio_inpaint, flags=cv2.INPAINT_TELEA)

# Guardar resultado intermedio
cv2.imwrite("foto_sin_rayones.jpg", img_restaurada)
print("Proceso de inpainting completado y guardado.")
⚠️ Advertencia: Si la máscara es demasiado grande o cubre detalles importantes del rostro, el algoritmo de inpainting podría borrar partes críticas de la fotografía. Ajusta el umbral con precaución.

🌈 Paso 2: Colorización Automática con Redes Neuronales Profundas

Una vez que la imagen está libre de rasgaduras y en escala de grises, el siguiente paso mágico es devolverle el color. Utilizaremos un modelo preentrenado basado en la investigación de Richard Zhang et al. (Colorful Image Colorization), integrado directamente en el módulo cv2.dnn de OpenCV.

Descarga y Configuración del Modelo Preentrenado

Para ejecutar este script, asegúrate de descargar los archivos de pesos y configuración del modelo:

  1. colorization_release_v2.caffemodel
  2. colorization_deploy_v2.prototxt
  3. pts_in_hull.npy
import os

# Rutas de los archivos del modelo
proto_file = "models/colorization_deploy_v2.prototxt"
model_file = "models/colorization_release_v2.caffemodel"
hull_file = "models/pts_in_hull.npy"

if not all(os.path.exists(f) for f in [proto_file, model_file, hull_file]):
    raise FileNotFoundError("Faltan los archivos del modelo de colorización en la carpeta 'models/'.")

# Cargar red neuronal
net = cv2.dnn.readNetFromCaffe(proto_file, model_file)

# Cargar los puntos de racimo de color (ab)
pts = np.load(hull_file)

# Configurar capas de la red con los puntos de color
class8 = net.getLayerId("class8_ab")
conv8 = net.getLayerId("conv8_313_rh")
pts = pts.transpose().reshape(2, 313, 1, 1)
net.blobs[class8].data[...] = pts.astype(np.float32)
net.blobs[conv8].data[...] = np.full((1, 313, 1, 1), 2.606, dtype=np.float32)

print("Modelo de colorización cargado correctamente en la red DNN.")

Procesamiento y Generación del Color

El modelo trabaja en el espacio de color CIELAB, donde el canal L representa la luminosidad (escala de grises) y los canales a y b representan las oposiciones cromáticas (verde-rojo y azul-amarillo). La red neuronal se encarga exclusivamente de predecir los canales a y b.

# Cargar la imagen restaurada previamente
img_gray_rgb = cv2.imread("foto_sin_rayones.jpg")

# Normalizar la imagen a escala [0, 1]
scaled = img_gray_rgb.astype("float32") / 255.0

# Convertir del espacio BGR a LAB
lab = cv2.cvtColor(scaled, cv2.COLOR_BGR2LAB)

# Extraer únicamente el canal L (Luminosidad)
l_channel = lab[:, :, 0]

# Redimensionar al tamaño esperado por la red (224x224)
resized = cv2.resize(l_channel, (224, 224))

# Restar la media de luminosidad estándar de ImageNet
mean_subtracted = resized - 50

# Crear un blob para la red neuronal
blob = cv2.dnn.blobFromImage(mean_subtracted)

# Realizar la inferencia
net.setInput(blob)
ab_inferido = net.forward()[0, :, :, :]

# Redimensionar la salida ab al tamaño original de la imagen
ab_inferido = cv2.resize(ab_inferido.transpose((1, 2, 0)), (img.shape[1], img.shape[0]))

# Unir el canal L original con los canales ab inferidos
lab_resultado = np.concatenate((l_channel[:, :, np.newaxis], ab_inferido), axis=2)

# Convertir de nuevo el espacio LAB a BGR
img_colorizada = cv2.cvtColor(lab_resultado, cv2.COLOR_LAB2BGR)
img_colorizada = np.clip(img_colorizada, 0, 1)
img_colorizada = (img_colorizada * 255).astype("uint8")

# Guardar resultado final
cv2.imwrite("foto_restaurada_y_colorizada.jpg", img_colorizada)
print("¡Colorización completada con éxito!")
💡 Consejo: Si notas que los colores se ven demasiado saturados o desvaídos, puedes ajustar la opacidad mezclando la imagen original en escala de grises con la imagen colorizada utilizando una ponderación lineal (`cv2.addWeighted`).

🎨 Paso 3: Post-Procesamiento y Mejora de Nitidez

A veces, el proceso de interpolación e inpainting puede dejar la imagen con una apariencia ligeramente borrosa. Para solucionar esto y dar un acabado profesional, aplicaremos un filtro de realce de bordes (Unsharp Masking) y un ajuste de contraste.

def mejorar_nitidez(imagen):
    # Aplicar desenfoque gaussiano para crear la máscara difusa
    gaussian = cv2.GaussianBlur(imagen, (0, 0), 2.0)
    
    # Restar la imagen difusa de la original para realzar los bordes
    nitida = cv2.addWeighted(imagen, 1.5, gaussian, -0.5, 0)
    return nitida

# Aplicar la función a nuestra imagen colorizada
img_final = mejorar_nitidez(img_colorizada)

# Guardar imagen optimizada
cv2.imwrite("foto_final_optimizada.jpg", img_final)
print("Post-procesamiento aplicado correctamente.")

❓ Preguntas Frecuentes (FAQ)

¿Puedo utilizar este método en fotografías en color muy degradadas?Sí, aunque este tutorial está enfocado en imágenes en escala de grises, puedes separar los canales de color originales, aplicar corrección de balance de blancos o convertir primero a escala de grises para aplicar una colorización moderna que unifique la paleta cromática.
¿Por qué la colorización a veces asigna colores incorrectos a ciertos objetos?Las redes neuronales de colorización automática se basan en el contexto visual aprendido durante su entrenamiento. Si un objeto (por ejemplo, un coche o una prenda de ropa) tiene un contexto ambiguo en escala de grises, la red asignará colores probables basados en estadísticas previas (como cielo azul o vegetación verde), pero no conoce la historia real del objeto.
¿Es posible ejecutar este código sin tarjeta gráfica (GPU)?Absolutamente. El código funcionará perfectamente utilizando la CPU, aunque el tiempo de procesamiento por imagen puede aumentar de unos pocos milisegundos a varios segundos dependiendo de la resolución de la fotografía.

🏁 Conclusión

La combinación de algoritmos clásicos de procesamiento de imágenes con modelos modernos de aprendizaje profundo abre un abanico infinito de posibilidades en la conservación del patrimonio visual. A lo largo de este tutorial, has aprendido a identificar y reparar daños físicos mediante inpainting, a insuflar vida y color a imágenes históricas utilizando redes neuronales profundas en OpenCV, y a aplicar técnicas de post-procesamiento para garantizar resultados estéticos de alta calidad. ¡Ahora es tu turno de desempolvar los viejos álbumes familiares y poner en práctica todo lo aprendido!

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!