¿Qué es OpenEXR?
OpenEXR es un formato de imagen de alto rango dinámico (HDR) desarrollado por Industrial Light & Magic (ILM) en 1999 y publicado como código abierto en 2003. Se ha convertido en el estándar de la industria para efectos visuales, renderizado 3D y producción cinematográfica — prácticamente todos los grandes estudios de VFX (ILM, Weta Digital, DNEG, Framestore), renderizadores (Arnold, V-Ray, RenderMan, Cycles) y aplicaciones de composición (Nuke, Fusion, After Effects) usan OpenEXR como formato de intercambio principal.
La característica definitoria de OpenEXR es su soporte para valores de píxeles en punto flotante — mientras que las imágenes estándar de 8 bits almacenan valores de 0 a 255, OpenEXR almacena valores como números en punto flotante de media precisión de 16 bits (float16) o precisión completa de 32 bits (float32), sin recorte en "blanco puro". Un sol en un archivo EXR puede tener un valor de 50.000 — 50.000 veces más brillante que un valor de 1,0 — mientras conserva el detalle de las sombras profundas.
Rango dinámico: por qué importa para VFX
En producción cinematográfica, el término luz lineal es fundamental. La luz física en el mundo real es lineal: el doble de fotones significa el doble de brillo. OpenEXR almacena datos de píxeles en luz lineal de escena — valores en punto flotante sin modificar, sin recortar, sin tone-mapping tal como salieron del renderizador o la cámara.
Esto significa:
- Sin banding en sombras o altas luces: el punto flotante tiene más precisión donde importa
- Sin recorte: las altas luces permanecen recuperables sin importar lo brillantes que sean
- Composición matemáticamente correcta: las operaciones de suma, multiplicación y filtrado funcionan correctamente en luz lineal
- Tone mapping diferido: la LUT o curva de tone mapping se aplica al final del pipeline
Estructura del archivo OpenEXR
Un archivo OpenEXR es un archivo binario con:
- Número mágico:
76 2F 31 01 - Campo de versión: indicadores de escaneo lineal vs teselado, parte única vs múltiple
- Cabecera: pares clave-valor de atributos incluyendo:
channels: la lista de canales (R, G, B, A, Z, normal.X, etc.)dataWindow: el rectángulo de datos de píxelesdisplayWindow: la región de visualización previstacompression: algoritmo de compresión
- Tabla de desplazamientos: desplazamientos de bytes a cada bloque para acceso aleatorio
- Datos de píxeles: datos de canal comprimidos
Tipos de datos y profundidad de bits
| Tipo | Bits | Rango | Caso de uso |
|---|---|---|---|
HALF |
Float 16 bits | ~6,1×10⁻⁵ a 65504 | VFX y composición principales |
FLOAT |
Float 32 bits | ~1,2×10⁻³⁸ a 3,4×10³⁸ | Mapas de sombra profunda, profundidad Z |
UINT |
Entero sin signo 32 bits | 0 a 4.294.967.295 | Mattes de objeto, cryptomatte |
Canales: más allá de RGBA
Una de las características más poderosas de OpenEXR es el soporte de canales arbitrarios. Un único archivo EXR puede almacenar docenas de pases de renderizado:
R, G, B, A # belleza (composite final) RGBA
diffuse.R, diffuse.G, diffuse.B # componente de iluminación difusa
specular.R, specular.G, specular.B # reflejos especulares
Z # profundidad (distancia desde la cámara)
normal.X, normal.Y, normal.Z # normales de superficie en espacio mundo
cryptomatte00.R, ... # mattes de objeto
ao # oclusión ambiental
velocity.X, velocity.Y # vectores de movimiento para motion blur
Este flujo de trabajo de EXR multi-canal / multi-pase es la base de la composición VFX moderna: el renderizador produce un único archivo EXR con todos los pases, y el compositor (Nuke, Fusion) puede combinarlos, ajustarlos y reencuadrarlos selectivamente sin volver a renderizar.
Algoritmos de compresión
| Compresión | Descripción | Mejor para |
|---|---|---|
NONE |
Sin compresión | Lectura/escritura más rápida |
PIZ |
Basado en wavelets | Mejor para imágenes naturales y renders fotorrealistas |
DWAA |
DreamWorks Animation, línea de escaneo | Mejor equilibrio ratio/velocidad para VFX |
DWAB |
DreamWorks Animation, bloque de 256 líneas | Ligeramente mejor que DWAA |
ZIP |
DEFLATE, bloques de 16 líneas | Buen equilibrio general |
B44 |
Compresión half-float con pérdida | Ratio fijo 2,28:1, decodificación muy rápida |
Trabajar con OpenEXR
Python con OpenEXR e Imath
# pip install OpenEXR Imath
import OpenEXR
import Imath
import numpy as np
# --- Leer un archivo EXR ---
exr = OpenEXR.InputFile('render.exr')
header = exr.header()
dw = header['dataWindow']
ancho = dw.max.x - dw.min.x + 1
alto = dw.max.y - dw.min.y + 1
print(f"Dimensiones: {ancho} x {alto}")
print(f"Canales: {list(header['channels'].keys())}")
HALF = Imath.PixelType(Imath.PixelType.HALF)
r_bytes = exr.channel('R', HALF)
g_bytes = exr.channel('G', HALF)
b_bytes = exr.channel('B', HALF)
r = np.frombuffer(r_bytes, dtype=np.float16).reshape(alto, ancho)
g = np.frombuffer(g_bytes, dtype=np.float16).reshape(alto, ancho)
b = np.frombuffer(b_bytes, dtype=np.float16).reshape(alto, ancho)
rgb = np.stack([r, g, b], axis=-1)
print(f"Valor máximo de píxel: {rgb.max():.2f}") # puede ser >> 1,0
# --- Escribir un archivo EXR ---
cabecera_salida = OpenEXR.Header(ancho, alto)
cabecera_salida['compression'] = Imath.Compression(Imath.Compression.PIZ_COMPRESSION)
canales = {
'R': r.astype(np.float16).tobytes(),
'G': g.astype(np.float16).tobytes(),
'B': b.astype(np.float16).tobytes(),
}
sal = OpenEXR.OutputFile('salida.exr', cabecera_salida)
sal.writePixels(canales)
sal.close()
Línea de comandos con oiiotool
# oiiotool — la navaja suiza del procesamiento de imágenes para VFX
# Convertir EXR a PNG (con tone mapping ACES)
oiiotool render.exr --ociodisplay "ACES" "sRGB" -o vista_previa.png
# Extraer un canal específico (profundidad Z)
oiiotool render.exr --ch Z -o profundidad.exr
# Convertir a TIFF de 16 bits
oiiotool render.exr -d uint16 -o salida.tiff
# Inspeccionar un archivo EXR
oiiotool --info -v render.exr
OpenEXR vs otros formatos HDR
| Formato | Profundidad de bits | Canales | Uso principal |
|---|---|---|---|
| OpenEXR | Float 16/32 bits | Arbitrarios | VFX, cine, renderizado |
| HDRI (.hdr, Radiance) | Mantisa 8 bits + exp | RGB | Mapas de entorno, IBL |
| TIFF | 8/16/32 bits entero | 4 (RGBA) | Impresión, médico, escaneo |
| DNG | 12-16 bits | Patrón BAYER | RAW de cámara |
| PNG (16 bits) | 16 bits entero | RGBA | Web, general sin pérdida |
La combinación de OpenEXR de precisión en punto flotante, canales arbitrarios, compresión sin pérdida y gestión de color estandarizada lo hace únicamente adecuado para flujos de trabajo de producción de imágenes profesionales donde la calidad y la corrección son innegociables.