Midiendo el rango dinámico de una cámara

Guillermo Luijk

Fujista de renombre
En webs como DxOMark o Photons to Photos (Bill Claff) se hacen mediciones del rango dinámico de un sensor. El procedimiento, elecciones particulares de cada uno al margen, es bastante estándar. Me ha pasado Hugo Rodríguez unos archivos de una Olympus OM-1 que permiten precisamente este cálculo. La idea es ver si el algoritmo fructifica en una app para que cada cual pueda medir el RD de su cámara (por cierto quien sepa generar ejecutables y pueda estar interesado que lo diga).

Pasos:

Se fotografían con la cámara parches de color uniforme poco expuestos: en este caso se muestra la toma a ISO12800. Se hace desenfocada sobre un monitor para no capturar la textura como ruido. El color magenta es para reducir los niveles verdes en el RAW relativos a los rojos y azules, y así tener valores más similares. En mi caso me ha dado igual porque solo tomaré el canal verde del RAW para la prueba:

parches_iso12800_carta.jpg


Del archivo RAW se extraen (con DCRAW) los datos RAW puros, es decir los valores numéricos sin revelar el RAW, y en concreto uno de los canales G de la matriz de Bayer. Con esos valores se construye una imagen monocroma a la que se corrige el error de perspectiva de la captura para poder identificar más fácilmente los parches. Aunque hay corrección geométrica no hay interpolación, todos los valores de la siguiente imagen son tal cual aparecían en el RAW (es lo que se llama "interpolación" nearest neighbour):

parches_iso12800.jpg



Acotados los parches que vana usarse, vemos que se desecha una buena parte de la imagen porque es más importante que el desenfoque no contamine los parches de sus vecinos que el disponer de muchos píxeles. Para mi gusto esta carta (es la que propone en su web Bill Claff), tiene demasiados parches. No hacen falta tantos, y con menos parches el método sería más robusto frente al desenfoque y la distorsión.

A continuación se lee en cada parche el nivel de señal útil o valor de exposición RAW (la media de valores RAW en el parche) así como el ruido (desviación estándar de los valores RAW en el parche, es una operación estadística perfectamente conocida). El cociente de ambos constituye la relación S/N:

S/N = Media(niveles en parche) / DesvEstandar(niveles en parche)

Nuestro objetivo precisamente es obtener las Curvas de relación S/N, que son las gráficas que nos dan la relación S/N (aquí la mostraremos en escala de decibelios=dB) para cada posible valor de señal (nivel de exposición RAW mostrado en pasos respecto a la saturación, la cual situamos en la referencia 0EV).

Cada parche de cada captura (Hugo me ha pasado 10 archivos RAW a todos los ISOs de la cámara) proporciona una muestra representada como un circulito rojo. La gráfica queda así:

snr_olympusOM1.png


Y qué tiene que ver esto con el Rango dinámico? todo. Sobre esas curvas, y elegido un criterio umbral de relación S/N mínima exigible para considerar el RD utilizable en fotografía, se mide cuantos pasos desde la saturación (el 0EV de la derecha en el eje X) hay hasta que se alcanza una relación S/N de 12dB (criterio fotográfico de ruido aceptable).

Por ejemplo si seguimos la curva de ISO800, vemos que cruza la línea horizontal de 12dB casi en el punto -8EV, por lo tanto la Olympus OM-1 ISO800 tiene unos 7,8-7,9 pasos de rango dinámico efectivo utilizable en fotografía.

Si os fijáis en la forma de las curvas, las de ISO200-800 van muy paralelas, y lo mismo el resto de ISO1600-ISO65535. El cambio de comportamiento no es un error, es más bien signo de que "algo se cuece" en las tripas de esta cámara, ya sea algún procesado software de ruido clandestino (malo), o por algún mecanismo hardware tipo dual-gain (bueno). Si miramos la gráfica de RD de Bill Claff para esta cámara, veremos un "salto" extraño en la tendencia justo tras ISO800:

snr_olympusOM1csClaff.png


Este tipo de cosas, que se ven mejor atendiendo al detalle de las Curvas de relación S/N, son las que explican los "saltos" y comportamientos aparentemente caprichosos del RD de ciertas cámaras vs el ISO.

Al que le guste la programación, aquí está todo:

Salu2!
 
Última edición:
Gracias guijarro. Bill confirma que la cámara cambia su comportamiento a partir de ISO800 por hardware: "Yes, the Olympus System OM-1 looks to have High Conversion Gain (HCG) starting at ISO 1000 (and Noise Reduction starting at ISO 16000)".

He añadido curvas splines de aproximación para dibujar las Curvas de relación S/N y automatizar el cálculo numérico del rango dinámico (para los 2 criterios típicos: fotográfico de 12dB e ingenieril de 0dB):

SNRcurves.png


iso200
60/77 patches used
Dynamic range for 12dB: 9.5EV
Dynamic range for 0dB: 11.9EV
iso400
66/77 patches used
Dynamic range for 12dB: 8.7EV
Dynamic range for 0dB: 11.3EV
iso800
69/77 patches used
Dynamic range for 12dB: 7.9EV
Dynamic range for 0dB: 10.5EV
iso1600
74/77 patches used
Dynamic range for 12dB: 7.1EV
Dynamic range for 0dB: 10.1EV
iso3200
74/77 patches used
Dynamic range for 12dB: 6.2EV
Dynamic range for 0dB: 9.2EV
iso6400
74/77 patches used
Dynamic range for 12dB: 5.2EV
Dynamic range for 0dB: 8.3EV
iso12800
75/77 patches used
Dynamic range for 12dB: 4.2EV
Dynamic range for 0dB: 7.3EV
iso25600
74/77 patches used
Dynamic range for 12dB: 3.2EV
Dynamic range for 0dB: 6.5EV
iso51200
43/77 patches used
Dynamic range for 12dB: 2.2EV
Dynamic range for 0dB: 5.4EV
iso65535
29/77 patches used
Dynamic range for 12dB: 1.2EV

Además he añadido restricciones a los parches para desechar el dato de aquellos que en realidad no nos interesan (nivel de señal tan bajo que su media da un valor negativo, relación S/N por debajo de -10dB, y parches que empiezan a mostrar píxeles saturados que desvirtuarían los cálculos). Ej. 43 parches/muestras usados de la toma ISO51200:

cropwithpatches_iso51200.jpg


Salu2!
 
Ya había leído que desde el ISO mínimo a los 800 los sensores se comporta an distinto que de 800 hacia arriba por la amplificación por HW que hacen. Tu explicación sirve para entender como funciona/comporta un sensor con relación al SN a distintos ISOs. ¿No tienes nada hecho con sensores Fuji?
 
Hacer una app no sería especialmente complejo, el tema es que no creo que es un procedimiento que luego vaya a seguir (casi) nadie.

Muy interesante en cualquier caso ;)
 
Lo sé, a la mayoría de la gente le gusta más estrenar cámara tras cámara que conocer a fondo la que ya tienen. Paradójicamente lo segundo es más barato e intelectualmente edificante que lo primero

En cualquier caso si alguien programa en cualquier lenguaje compilable y le gustaría intentarlo que lo diga. Es la idea que tiene Hugo en mente. A mí solo me interesa escribir los algoritmos.

Salu2!
 
Vamos afinando el programa. Análisis de otra cámara que tiene Hugo, la Sony A7 IV.

Las curvas de relación S/N, de las que se derivan los cálculos de rango dinámico pero que son por sí solas una maravilla para poder conocer cosas sobre el rendimiento del sensor, tienen el siguiente aspecto:


SNRcurves.png


Viéndolas sabemos:
  • ISO50 e ISO100 son exactamente la misma cosa a nivel RAW en esta cámara. La prueba es que sus dos curvas se solapan.
  • A partir de ISO400 entra en funcionamiento una segunda electrónica del sensor, y solo hay que comparar las curvas de ISO400-51200 con ISO50-200 para darse cuenta. La curva de ISO400 cruza a la de ISO200, esto quiere decir que en las sombras hiper profundas el sensor rinde incluso mejor a ISO400 que a ISO200.
  • Las curvas ISO102400 e ISO204800 claramente delatan (por el aumento de relación S/N tan extraño), que Sony aplica en ellas reducciones de ruido clandestinas sobre los propios datos RAW

De las anteriores curvas se deriva el cálculo de rango dinámico, que comparado con las cifras de Photons to Photos queda así:

DRvsBillClaff.png


Antes de que alguien piense que nuestro cálculo está mal, es todo lo contrario. Las cifras no coinciden al milímetro porque Bill Claff hace una normalización sobre los datos (por la cual le hemos preguntado un par de veces pero responde con evasivas así que no vamos a incordiarle más). Lo importante para validar nuestro cálculo es que, dejando de lado esa normalización, que explicaría el gap constante entre ambas curvas, las dos se siguen perfectamente:
  • ISO50 muy similar a ISO100 (el nuestro en realidad es más preciso, nos salen más iguales esos dos ISO que deberían serlo)
  • Boost a ISO400 por el Dual gain del sensor comentado
  • ISO invarianza absoluta (pérdida de 1 paso de RD por cada paso que subimos ISO) hasta ISO51200
  • Y finalmente los RD de los ISOs procesados (102400 y 204800). Tengo que ser franco: viendo nuestras curvas de relación S/N me fío más de nuestro cálculo en estos dos ISO que del de Photons to Photos, que quizá fue víctima del comportamiento tan extraño que provoca la reducción de ruido aplicada por Sony. En cualquier caso siendo cifras de RD infladas por la reducción de ruido no tienen ningún interés.

Para comprobar la estabilidad de los cálculos, Hugo a disparado con la misma cámara sobre la carta de colores en circunstancias diferentes: otro monitor, de noche para reducir brillos, y dedicando a la carta solo una fracción del encuadre. Las curvas de relación S/N de ambas series resultan clónicas, demostración de lo robusta que es la forma de medir RD con parches. Cuando ploteamos las dos curvas de RD a cada ISO:

comp_rd_sonya7iv.png


Cuesta creer que haya dos gráficas. El RD calculado a todos los ISO (salvo los extremos 102400 y 204800) sale parejo hasta el segundo decimal, y una curva cubre a la otra impidiendo ver su color. Esto da pistas de que incluso disparando la carta en condiciones un poco de andar por casa se podrán tener cálculos de RD muy precisos.

Por qué una herramienta así si ya está Photons to Photos?
  • Porque Photons to Photos muestra cifras con una normalización que no explican. Nosotros las vamos a explicar claramente.
  • Porque vamos un punto más allá en la finura del cálculo (Photons to Photos usa el nivel de negro entero informado en los metadatos, nosotros lo calculamos a partir de un RAW y empleando decimales). El nivel de negro es crítico para estimar correctamente las mediciones de ruido.
  • Porque estarás midiendo el RD de tu cámara, no solo de tu modelo de cámara (una de las pruebas que nos apetece hacer es comparar el RD de dos unidades de un mismo modelo; o también comparar una unidad consigo misma en frío vs cuando está muy caliente. p.ej. tras grabar vídeo).
  • El programa no solo va a servir para calcular el RD, sino para generar la propia carta a la que disparar, para calcular con precisión los niveles de negro y saturación del sensor (esto en realidad es más una curiosidad científica para el fotógrafo que un dato útil), y también planeamos que sirva para medir el rendimiento completo del sensor en cualquier circunstancia (sería llevar la curva de relación S/N hasta la saturación).

Para ir abriendo boca, y aunque el programa tendrá un GUI intuitivo de utilizar (arrastras ficheros, botones,...), pongo aquí los comandos del CLI (módulo de consola):

Código:
C:\>rango

Digital camera Dynamic Range calculation "rango" v1.0
by Juan Manuel Font (coding), Hugo Rodriguez (UI design) and Guillermo Luijk (algorithms)

Usage: rango [OPTION]... [FILE]...

--chart               -c <R G B invgamma> : Create test chart in PNG format ranging colours from (0,0,0) to (R,G,B) with gamma compression (default R=255, G=101, B=164, invgamma=1.4)
--black-level         -b <float>          : Camera RAW black level
--black-file          -B <file>           : Totally dark RAW file ideally shot at base ISO
--saturation-level    -s <float>          : Camera RAW saturation level
--saturation-file     -S <file>           : Totally clipped RAW file ideally shot at base ISO
--input-files         -i <files>          : Input RAW files shot over the test chart ideally for every ISO
--patch-ratio         -r <float>          : Relative patch width/height used to compute signal and noise readings (default=0.5)
--snrthreshold-db     -d <float>          : SNR threshold in dB for DR calculation (default=12dB (photo DR) plus 0dB (engineering DR))
--drnormalization-mpx -m <float>          : Number of Mpx for DR normalization (default=8Mpx)
--poly-fit            -f <int 2-3>        : Polynomic order (default=3) to fit the SNR curve
--output-file         -o <file>           : Output CSV text file(s) with all results: black level, sat level, SNR samples, DR values, fitting params (default="results.csv")
--plot                -p <int 0-2>        : Export SNR curves in PNG format with/without the CLI command that generated them (default=0, don't plot)


La mascota (casi) definitiva de la parte CLI:

rangofujistas.png
 
Última edición:
El GUI funcionaría así:

Se introducen 3 grupos de archivos:
  • Un darkframe de la cámara para calcular con mucha precisión su nivel de negro (la mayoría de programas se basan en el número entero que aparece en los metadatos)
  • Un RAW saturado para conocer el punto de saturación de la cámara (normalmente el fondo de la escala)
  • Todas las capturas a la carta de colores que hayamos hecho (típicamente una para cada ISO del que se quiera calcular el RD)

gui1.png


Se le da a Ejecutar y el programa va mostrando el progreso de los cálculos: puede verse el nivel de negro y saturación, así como los parámetros con que se ha calculado el RD en este caso (y que podrán cambiarse): relación S/N de 12dB (lo que se llama rango dinámico "fotográfico") y 0dB (rango dinámico ingenieril), normalización a 8Mpx (como hace DxOMark), y luego detalles del tipo de ajuste (polinomio cúbico) y de la porción central de los parches usada para los cálculos (50%):

gui2.png



Terminados los cálculos en unos pocos segundos, se tienen las cifras de rango dinámico y las interesantísimas curvas de relación S/N, que modelan cómo funciona el sensor en las sombras profundas para cada ISO:

gui3.png



Aquí las curvas ampliadas:

snrolympus8mpx.png


Aún queda pero está quedando fina la herramienta. Por cierto la estamos haciendo entre Juan Manuel Font (programador), Hugo Rodríguez (UI) y yo (algoritmos).

Salu2!
 
Atrás
Arriba