Pirámides de imágenes
Todo el código de ejemplo se encuentra en Google Colab para su ejecución directa. Si no puedes ejecutar OpenCV localmente, puedes usar Google Colab junto con matplotlib para visualizar imágenes. Además las imágenes que se utilizaran en los ejemplos son naranja.jpg y manzana.jpg.
Objetivo
- Comprender qué es una pirámide de imágenes.
- Aprender a usar
cv.pyrDown()ycv.pyrUp()para generar diferentes niveles de resolución. - Entender la utilidad de las pirámides en procesamiento de imágenes (detección, blending, reducción de ruido).
- Implementar ejemplos prácticos de construcción de pirámides y fusión de imágenes.
Conceptos clave
- Pirámide de imágenes: Representación de una imagen en varios niveles de resolución.
- Pirámide Gaussiana: Se obtiene reduciendo progresivamente la imagen (
pyrDown). - Pirámide Laplaciana: Representa las diferencias entre los niveles de la pirámide gaussiana y se usa para reconstrucción y blending.
- pyrDown(): Reduce la resolución de la imagen a la mitad en cada nivel.
- pyrUp(): Aumenta la resolución al doble, interpolando píxeles.
Funciones principales en OpenCV
-
cv.pyrDown(): Reduce el tamaño de la imagen a la mitad (suavizado + reducción). -
cv.pyrUp(): Aumenta el tamaño de la imagen al doble, interpolando los valores de los píxeles.
Teoría
Una pirámide de imágenes es una colección de imágenes obtenidas a partir de la misma imagen original pero en diferentes resoluciones. La idea es procesar primero una versión pequeña (más rápida de analizar) y luego refinar con versiones de mayor resolución.
Existen dos tipos principales:
-
Pirámide Gaussiana: Se obtiene aplicando repetidamente
pyrDown(). Cada nivel es una versión reducida y suavizada de la imagen. -
Pirámide Laplaciana: Se construye restando la expansión (
pyrUp()) de un nivel gaussiano del nivel anterior. Se usa mucho para blending de imágenes y reconstrucción.
Ejemplo de interpretación:
- Los primeros niveles conservan solo la forma global de la imagen.
- Los niveles más altos (Laplace) contienen los detalles y bordes finos.
Construcción de pirámide Gaussiana y expansión
- Python (PC con entorno gráfico)
- Python (Google Colab)
import cv2 as cv
import matplotlib.pyplot as plt
# Leer imagen original
img = cv.imread("naranja.jpg")
# Crear pirámide de baja resolución (6 niveles)
# -----------------------------
low_res = [img.copy()]
for i in range(5): # en total 6 imágenes (original + 5 reducciones)
low_res.append(cv.pyrDown(low_res[-1]))
# Crear versión "high resolution" de cada nivel
high_res = []
for lr in low_res:
hr = cv.pyrUp(lr)
high_res.append(hr)
plt.figure(figsize=(18,6))
for i in range(6):
plt.subplot(2,6,i+1)
plt.imshow(cv.cvtColor(low_res[i], cv.COLOR_BGR2RGB))
plt.title(f"Low {i}")
plt.axis("off")
plt.subplot(2,6,i+7)
plt.imshow(cv.cvtColor(high_res[i], cv.COLOR_BGR2RGB))
plt.title(f"High {i}")
plt.axis("off")
plt.tight_layout()
plt.show()
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from google.colab import files
# Subir imagen
uploaded = files.upload()
filename = list(uploaded.keys())[0]
# Leer imagen original
img = cv.imread(filename)
# Crear pirámide de baja resolución (6 niveles)
# -----------------------------
low_res = [img.copy()]
for i in range(5): # en total 6 imágenes (original + 5 reducciones)
low_res.append(cv.pyrDown(low_res[-1]))
# Crear versión "high resolution" de cada nivel
high_res = []
for lr in low_res:
hr = cv.pyrUp(lr)
high_res.append(hr)
plt.figure(figsize=(18,6))
for i in range(6):
plt.subplot(2,6,i+1)
plt.imshow(cv.cvtColor(low_res[i], cv.COLOR_BGR2RGB))
plt.title(f"Low {i}")
plt.axis("off")
plt.subplot(2,6,i+7)
plt.imshow(cv.cvtColor(high_res[i], cv.COLOR_BGR2RGB))
plt.title(f"High {i}")
plt.axis("off")
plt.tight_layout()
plt.show()
Reconstrucción desde una imagen reducida
- Python (PC con entorno gráfico)
- Python (Google Colab)
import cv2 as cv
import matplotlib.pyplot as plt
# Leer imagen original
img = cv.imread("naranja.jpg")
# Bajar hasta la resolución más baja (6 niveles)
# -----------------------------
low_res = img.copy()
for i in range(3): # aplicar pyrDown 5 veces
low_res = cv.pyrDown(low_res)
# Subir otra vez hasta tamaño original
# -----------------------------
high_res = low_res.copy()
for i in range(5): # aplicar pyrUp 5 veces
high_res = cv.pyrUp(high_res)
# Ajustar al tamaño original (puede variar algunos píxeles por redondeo)
high_res = cv.resize(high_res, (img.shape[1], img.shape[0]))
plt.figure(figsize=(12,6))
plt.subplot(1,3,1)
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.title("Imagen Original")
plt.axis("off")
plt.subplot(1,3,2)
plt.imshow(cv.cvtColor(low_res, cv.COLOR_BGR2RGB))
plt.title("Low Resolution (nivel 5)")
plt.axis("off")
plt.subplot(1,3,3)
plt.imshow(cv.cvtColor(high_res, cv.COLOR_BGR2RGB))
plt.title("Reconstrucción (pyrUp)")
plt.axis("off")
plt.tight_layout()
plt.show()
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from google.colab import files
# Subir imagen
uploaded = files.upload()
filename = list(uploaded.keys())[0]
# Leer imagen original
img = cv.imread(filename)
# Bajar hasta la resolución más baja (6 niveles)
# -----------------------------
low_res = img.copy()
for i in range(3): # aplicar pyrDown 5 veces
low_res = cv.pyrDown(low_res)
# Subir otra vez hasta tamaño original
# -----------------------------
high_res = low_res.copy()
for i in range(5): # aplicar pyrUp 5 veces
high_res = cv.pyrUp(high_res)
# Ajustar al tamaño original (puede variar algunos píxeles por redondeo)
high_res = cv.resize(high_res, (img.shape[1], img.shape[0]))
plt.figure(figsize=(12,6))
plt.subplot(1,3,1)
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.title("Imagen Original")
plt.axis("off")
plt.subplot(1,3,2)
plt.imshow(cv.cvtColor(low_res, cv.COLOR_BGR2RGB))
plt.title("Low Resolution (nivel 5)")
plt.axis("off")
plt.subplot(1,3,3)
plt.imshow(cv.cvtColor(high_res, cv.COLOR_BGR2RGB))
plt.title("Reconstrucción (pyrUp)")
plt.axis("off")
plt.tight_layout()
plt.show()
Fusión de imágenes con pirámides Laplacianas
- Python (PC con entorno gráfico)
- Python (Google Colab)
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# Leer imagen original
img1 = cv.imread("naranja.jpg")
img2 = cv.imread("manzana.jpg")
# Ajustar ambas imágenes al mismo tamaño
height, width = img1.shape[:2]
img2 = cv.resize(img2, (width, height))
# Generar pirámide gaussiana para img1
# ------------------------------------
G = img1.copy()
gpImg1 = [G]
for i in range(6):
G = cv.pyrDown(G)
gpImg1.append(G)
# Generar pirámide gaussiana para img2
# ------------------------------------
G = img2.copy()
gpImg2 = [G]
for i in range(6):
G = cv.pyrDown(G)
gpImg2.append(G)
# Generar pirámide laplaciana para img1
# ------------------------------
lpImg1 = [gpImg1[5]]
for i in range(5,0,-1):
GE = cv.pyrUp(gpImg1[i])
GE = cv.resize(GE, (gpImg1[i-1].shape[1], gpImg1[i-1].shape[0]))
L = cv.subtract(gpImg1[i-1], GE)
lpImg1.append(L)
# Generar pirámide laplaciana para img2
# ------------------------------
lpImg2 = [gpImg2[5]]
for i in range(5,0,-1):
GE = cv.pyrUp(gpImg2[i])
GE = cv.resize(GE, (gpImg2[i-1].shape[1], gpImg2[i-1].shape[0]))
L = cv.subtract(gpImg2[i-1], GE)
lpImg2.append(L)
# Combinar mitad izquierda de img1 y mitad derecha de img2 en cada nivel
# ------------------------------
LS = []
for la,lb in zip(lpImg1,lpImg2): #zip():
rows,cols,dpt = la.shape
ls = np.hstack((la[:,0:cols//2], lb[:,cols//2:])) # np.hstack concatena matrices horizontalmente
LS.append(ls)
# Reconstrucción desde la pirámide laplaciana
# ------------------------------
ls_ = LS[0]
for i in range(1,6):
ls_ = cv.pyrUp(ls_)
ls_ = cv.resize(ls_, (LS[i].shape[1], LS[i].shape[0]))
ls_ = cv.add(ls_, LS[i]) # Sumar dos imágenes del mismo tamaño
# Imagen de comparación: mitad izquierda de img1 y mitad derecha de img2 pegadas directamente
# ------------------------------
real = np.hstack((img1[:,:cols//2], img2[:,cols//2:]))
# Mostrar resultados con Matplotlib
# ------------------------------
titles = [
"Imagen 1", "Imagen 2",
"Combinación directa (corte duro)",
"Blending con pirámide Laplaciana"
]
images = [img1, img2, real, ls_]
plt.figure(figsize=(12,6))
for i in range(4):
plt.subplot(2,2,i+1)
plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
plt.title(titles[i])
plt.axis("off")
plt.tight_layout()
plt.show()
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from google.colab import files
# Subir archivo desde tu PC
uploaded = files.upload()
filename = list(uploaded.keys())
img1 = cv.imread(filename[0])
img2 = cv.imread(filename[1])
# Ajustar ambas imágenes al mismo tamaño
height, width = img1.shape[:2]
img2 = cv.resize(img2, (width, height))
# Generar pirámide gaussiana para img1
# ------------------------------------
G = img1.copy()
gpImg1 = [G]
for i in range(6):
G = cv.pyrDown(G)
gpImg1.append(G)
# Generar pirámide gaussiana para img2
# ------------------------------------
G = img2.copy()
gpImg2 = [G]
for i in range(6):
G = cv.pyrDown(G)
gpImg2.append(G)
# Generar pirámide laplaciana para img1
# ------------------------------
lpImg1 = [gpImg1[5]]
for i in range(5,0,-1):
GE = cv.pyrUp(gpImg1[i])
GE = cv.resize(GE, (gpImg1[i-1].shape[1], gpImg1[i-1].shape[0]))
L = cv.subtract(gpImg1[i-1], GE)
lpImg1.append(L)
# Generar pirámide laplaciana para img2
# ------------------------------
lpImg2 = [gpImg2[5]]
for i in range(5,0,-1):
GE = cv.pyrUp(gpImg2[i])
GE = cv.resize(GE, (gpImg2[i-1].shape[1], gpImg2[i-1].shape[0]))
L = cv.subtract(gpImg2[i-1], GE)
lpImg2.append(L)
# Combinar mitad izquierda de img1 y mitad derecha de img2 en cada nivel
# ------------------------------
LS = []
for la,lb in zip(lpImg1,lpImg2): #zip():
rows,cols,dpt = la.shape
ls = np.hstack((la[:,0:cols//2], lb[:,cols//2:])) # np.hstack concatena matrices horizontalmente
LS.append(ls)
# Reconstrucción desde la pirámide laplaciana
# ------------------------------
ls_ = LS[0]
for i in range(1,6):
ls_ = cv.pyrUp(ls_)
ls_ = cv.resize(ls_, (LS[i].shape[1], LS[i].shape[0]))
ls_ = cv.add(ls_, LS[i]) # Sumar dos imágenes del mismo tamaño
# Imagen de comparación: mitad izquierda de img1 y mitad derecha de img2 pegadas directamente
# ------------------------------
real = np.hstack((img1[:,:cols//2], img2[:,cols//2:]))
# Mostrar resultados con Matplotlib
# ------------------------------
titles = [
"Imagen 1", "Imagen 2",
"Combinación directa (corte duro)",
"Blending con pirámide Laplaciana"
]
images = [img1, img2, real, ls_]
plt.figure(figsize=(12,6))
for i in range(4):
plt.subplot(2,2,i+1)
plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
plt.title(titles[i])
plt.axis("off")
plt.tight_layout()
plt.show()