Suma elemental y gestión del desbordamiento
La operación fundamental para combinar dos matrices de píxeles es cv2.add(). A diferencia de las sumas aritméticas tradicionales, esta función aplica saturación binaria: si el resultado excede el rango máximo del tipo de dato (ej. 255 para uint8), se corta al límite superior en lugar de desbordarse.
Especificación de parámetros
src1,src2: Entradas de igual tamaño y canalidad, o un arreglo y un escalar.dst: Arreglo de salida opcional. Si se omite, OpenCV asigna automáticamente memoria correspondiente.mask: Matriz de bits que indica qué rgeiones participar en la operación. Los píxeles marcados con cero permanecen inalterados o se establecen a fondo negro según la lógica interna.dtype: Control explícito del tipo de retorno; su ausencia deriva en inferencia automática basada en las entradas.
Implementación comparativa con NumPy
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# Configuración gráfica unificada
plt.rcParams.update({'font.sans-serif': ['Arial'], 'axes.unicode_minus': False})
# Carga y región de interés
ruta_origen_a = 'plano_superior.png'
ruta_origen_b = 'plano_inferior.png'
zona_vertical = slice(320, 510)
zona_horizontal = slice(150, 920)
captura_base = cv.imread(ruta_origen_a)[zona_vertical, zona_horizontal, :]
captura_secundaria = cv.imread(ruta_origen_b)[zona_vertical, zona_horizontal, :]
# Aplicar operaciones contrastadas
suma_opencv = cv.add(captura_base, captura_secundaria)
suma_numpy = captura_base + captura_secundaria # Comportamiento módulo 256
# Renderizado en cuadrícula
grafico, ejes = plt.subplots(2, 2, figsize=(12, 9))
etiquetas = ['Fuente A', 'Fuente B', 'Fusión OpenCV', 'Acumulación NumPy']
for i, frame in enumerate([captura_base, captura_secundaria, suma_opencv, suma_numpy]):
f, c = divmod(i, 2)
ejes[f, c].imshow(cv.cvtColor(frame, cv.COLOR_BGR2RGB))
ejes[f, c].set_title(etiquetas[i])
ejes[f, c].axis('off')
plt.tight_layout()
plt.show()
El comportamiento diferencial se vuelve evidente al evaluar vectores unitarios aislados:
>>> x_val = np.uint8([250])
>>>> y_val = np.uint8([15])
>>>> cv.add(x_val, y_val)
array([[255]], dtype=uint8) # Límite aplicado
>>>> x_val + y_val
array([9], dtype=uint8) # Desbordamiento modular (265 % 256)
Composición lineal y transparencia controlada
Cuando el objetivo es superponer dos capturas preservando sus rasgos dominantes sin perder información, se recurre a la interpolación ponderada. La ecuación matemática subyacente sigue la estructura:
resultado = α · fuente_uno + β · fuente_dos + γ
Donde α y β definen la contribución relativa de cada capa visual, mientras γ actúa como un desplazamiento lumínico constante que permite ajustar el brillo global de la composición.
Sinatxis de la rutina de mezcla
cv2.addWeighted(src1, alpha, src2, beta, gamma, dst=None, dtype=-1)
Ejemplo de integración práctica
# Retomando los arreglos cargados previamente
peso_primary = 0.65
peso_secondary = 0.35
compensacion_luminica = 12.0
capa_fusionada = cv.addWeighted(
captura_base,
peso_primary,
captura_secundaria,
peso_secondary,
compensacion_luminica
)
# Verificación visual lado a lado
visualizador, paneles = plt.subplots(1, 2, figsize=(14, 5))
paneles[0].imshow(cv.cvtColor(captura_base, cv.COLOR_BGR2RGB))
paneles[0].set_title('Captura Origen')
paneles[0].axis('off')
paneles[1].imshow(cv.cvtColor(capa_fusionada, cv.COLOR_BGR2RGB))
titulo_final = f'Fusión Lineal (α={peso_primary}, β={peso_secondary})'
paneles[1].set_title(titulo_final)
paneles[1].axis('off')
plt.show()