domingo, 3 de junio de 2018

Decodificación de archivos RAW con R

Gracias a su notación vectorial, R resulta cómodo para almacenar y operar con imágenes en forma matricial. En este artículo vamos a usar esta facilidad para leer y procesar archivos RAW procedentes de cámaras digitales.

Como se explicaba en 'Histogramas RAW en cámaras digitales. Petición en CHANGE.ORG', un archivo RAW vendría a ser como un negativo digital. Consiste en un conjunto de datos numéricos con la información bruta capturada por el sensor, y todas las cámaras digitales (incluso tu móvil) lo generan como paso previo a la construcción de la imagen final en formato JPEG.

La captura de color es parcial porque cada fotocaptor del sensor solo registra una de las tres componentes: roja, verde o azul, siguiendo en la mayoría de cámaras una distribución de filtros de color conocida como matriz de Bayer.

Fuente: Wikipedia


Para convertirse en una imagen visualizable en color, el RAW requiere de un procesado denominado por analogía revelado RAW y que comprende como mínimo las siguientes tres etapas:


  • Balance de blancos: escalado lineal de los niveles relativos de cada canal RGB, con la finalidad de compensar la sensibilidad espectral nativa del sensor y adecuarnos a la temperatura de color de la escena (luz de día, tungsteno, flash,...).
  • Demosaicing: interpolación en cada píxel de los dos valores RGB no capturados por el sensor, a partir de la información parcial disponible. Existen diferentes algoritmos con sus fortalezas y debilidades (VNG, AHD, AMaZE,...).
  • Conversión a espacio de color: mapeo, generalmente matricial, de los valores RGB resultantes a un espacio de color estándar (sRGB, Adobe RGB, ProPhoto RGB,...), para lograr una correcta reproducción de luminosidad (gamma) y color en el dispositivo de salida.

En un flujo de trabajo real, cualquier cámara añade a las fases anteriores procesos de reducción de ruido, enfoque y ajustes de contraste y saturación de color. Si pensabas que una fotografía es un fiel reflejo de la realidad puedes desde este mismo momento quitarte esa idea de la cabeza.

Cada fabricante de cámaras digitales tiene un formato RAW propietario (CR2 de Canon, NEF de Nikon, ARW de Sony,...), que incluso cambia de un modelo a otro. Para decodificar los distintos formatos RAW parametrizaremos desde R una llamada a DCRAW, decodificador/revelador RAW de línea de comandos diseñado por David Coffin capaz de leer prácticamente cualquier formato RAW (NOTA: si DCRAW no soporta tu cámara una conversión previa a DNG soluciona el problema).

Fuente: David Coffin


Si quieres profundizar sobre DCRAW, en dcraw.c está el código fuente original del programa, en dcraw.exe una compilación para Windows (64 bits) y aquí un tutorial sobre DCRAW que escribí hace tiempo.

Fuente: DCRAW


Para leer los archivos RAW conservando la estructura de la matriz de Bayer, solo usaremos las opciones -D (decodificación RAW pura) y -d (decodificación RAW con escalado lineal) de DCRAW.

~~~

Ahora construimos una librería básica de funciones para leer y manipular los datos RAW desde R, y las aplicamos sobre el RAW de una fotografía real.




Empezamos por cargar el archivo RAW de la fotografía en una matriz con la función LoadRAW() y visualizamos la estructura del mosaico Bayer.



O si se prefiere, coloreando en la posición de cada fotocaptor con el canal correspondiente para hacer más patente el patrón RG/GB.



A continuación deshacemos el mosaico de Bayer con DebayerRAW(), que por defecto combina cada grupo de 2x2 fotocaptores RG1/G2B del sensor en un único píxel de color (R, (G1+G2)/2, B). No constituye un demosaicing ortodoxo pero nos permite tener una imagen visible y en color.



Esto es lo más cerca que podemos estar de conocer el color tal y como lo "ve" la cámara. Haciendo clic sobre la imagen la vemos en su resolución nativa, que corresponde a la mitad de ancho y alto del RAW original por la combinación realizada.

Sobre la anterior imagen vamos a ver la distribución de niveles RGB en el archivo RAW con la función HistRAW(), que dibuja los tres histogramas RGB superpuestos. Como no se ha hecho ningún tipo de procesado sobre los datos RAW puede afirmarse que este gráfico constituye un histograma genuino del RAW, algo que por desgracia ni las cámaras ni los reveladores RAW comerciales muestran.



El canal verde es el que alcanza niveles más altos debido principalmente a la mayor sensibilidad del sensor en esa banda, de ahí la tonalidad verdosa de la imagen que obtuvimos. El minúsculo pico del extremo derecho corresponde a fotocaptores verdes saturados por reflejos quasi especulares, en concreto en el portón trasero del vehículo.

Aplicando el balance de blancos con la función WhitebalanceRAW(), los canales se alinean haciendo que la imagen adquiera colores más naturales.



A falta de una conversión a un espacio de color estándar de salida, estos aún no son los colores definitivos que debiera tener la imagen pues seguimos de algún modo en el espacio del sensor, pero se aproximan mucho y ya no nos resultan tan extraños como el tono verdoso previo al balance de blancos. Haciendo clic sobre la imagen puede verse esta versión balanceada en su resolución nativa.

Los multiplicadores a aplicar como balance de blancos dependen de la cámara en cuestión pudiendo conocerse mediante DCRAW, y lo mismo sucede con el patrón de Bayer usado, que por defecto se considera RG/GB existiendo otras tres tipologías posibles (BG/GR, GR/BG y GB/RG).

Para obtener las imágenes se han usado las funciones ShowRAW() y SaveRAW(), que permiten respectivamente mostrar en el editor de R y sacar a un fichero externo los archivos RAW procesados con el resto de funciones. Admiten tanto datos RAW puros (en cuyo caso la salida será monocroma con el patrón de Bayer visible), como los resultantes de nuestro demosaicing simplificado (en cuyo caso serán imágenes en color).

~~~

Manejadas las primitivas básicas, vamos a averiguar cómo de correlada está la información que captura un sensor Bayer. Nos ayudamos del paquete qgraph para representar las correlaciones entre los canales R, G1, G2 y B.



Como era esperable hay una alta correlación espacial, especialmente entre G1 y G2 ya que emplean el mismo filtro espectral. Respecto a los demás emparejamientos posibles vemos que los canales G1 y G2 se "llevan" mejor con B que con R, los cuales correlan muy poco entre ellos.

Dibujamos ahora gráficas de dispersión. Empezamos enfrentando G1 y G2 donde además de la alta correlación corroboramos la lógica relación 1:1 existente entre ambos.



Cuando dibujamos B frente a G1, nos encontramos con dos correlaciones claramente diferenciadas entre ambos canales. El motivo es que la imagen se divide en sendas zonas de tonalidad muy uniforme: el cielo y la tierra, en cada una de las cuales la correlación lineal es muy fuerte pero con diferente proporcionalidad.



Al calcular correlaciones en cada una de las áreas por separado se tienen afinidades entre canales mucho más intensas que la detectada a nivel global.



Aunque globalmente R estaba menos correlado con los canales G1 y G2 que B, en zonas de color uniforme es al contrario y R es más afín a los canales G que B. En general en zonas de tono uniforme donde solo cambia la luminosidad, la correlación lineal entre los tres canales siempre será muy alta.

El código se ha vectorizado para no usar bucles en ningún caso, por lo que su ejecución es muy rápida pese a que una fotografía en alta resolución implica procesar varios millones de datos numéricos.

~~~

Repositorio con el código R: GitHub. Archivo RAW original: namibia.cr2.

4 comentarios:

  1. Hola Guillermo, muchas gracias por el tutorial. Hace tiempo en algo relacionado, por esta misma vía te consulté cómo acceder a los datos RAW a través de Fortran - lenguaje que manejo. El asunto era al final complejo si se pretendía acceder directamente, aunque claro está que se puede - mejor probablemente con C. En todo caso, en este tutorial apuntas a lo que ya sospechaba hace un tiempo: acceder a través de R, y si es necesario luego comunicarlo con Fortran - se puede desde R. En todo caso veo que propones utilizar comandos que ya están en R para las funciones básicas.
    Yo últimamente estoy probando un programa de soft libre que creo que se basa también en dcraw, y que seguro que conoces, RawTherapee. Aparte de que no haya mucha documentación y de que su uso es algo complejo, 'me he peleado' con él, y estoy más que satisfecho - enormemente superior a ACR de PS, en mi opinión. No sé, ahora tengo dudas de si merece la pena invertir en el tratamiento directo con R.

    ResponderEliminar
  2. Te agradecería colocar las funciones en R completas para poder utilizar el procedimiento. Mil gracias.

    ResponderEliminar

Por claridad del blog, por favor trata de utilizar una sintaxis lo más correcta posible y no abusar del uso de emoticonos, mayúsculas y similares.