PDA

Ver la versión completa : Sobre el control de Exposición



Guillermo Luijk
25/05/2008, 21:09
Me vuelvo loco cada vez buscando donde puse el último código así que abro este hilo.

Esto fue lo último que comentamos en distintos hilos:


¿Mantengo lo anterior como una opción?

De hecho mantelo como la única opción cuando f>1, va a ser lo mejor. Forzando que el descenso de sobreexposición baje a 0EV en lineal (abajo-der.), se obtienen sobreexposiciones que saturan la luminosidad (abajo-izq.). Además cualquier esquema que supusiera una curva por encima de las rectas de la gráfica sup.-izq. implicaría más facilidad de saturación parcial así que ya que el esquema actual no crea extraños lo dejamos así.


http://img294.imageshack.us/img294/6192/preserves4.gif


Para f<1 sí por favor prueba lo que he propuesto, creo que mejorará. Si es así el esquema final de curvas quedaría:


http://img294.imageshack.us/img294/3941/finalqy1.gif


Otro esquema que puede dar resultados muy interesantes, o como poco curiosos, es el de usar las curvas que ya tenemos definidas pero con una definición diferente de la luminosidad como el máximo de los canales: Y=max(R,G,B), tal como se hace en el modelo de color HSV (http://en.wikipedia.org/wiki/HSV_color_space).

Según ese esquema los colores más saturados tendrán mayor luminosidad y se sobre/subexpondrán menos. El resultado puede ser curioso; lo cierto es que por mucha sobreexposición que se aplique, nunca se va a alterar el tono de un solo píxel porque no habrá saturaciones parciales. Esto deberá respetar el verde de tus hojas al subir la exposición, si bien las puede dejar estancadas en una determinada luminosidad cuando su entorno menos saturado sigue ganando brillo.

Originalmente publicado por _GUI_
He estado dándole vueltas al control de exposición.
El modo de aumento (f>1) la verdad que no me preocupa mucho qué modelo escojamos al final, porque en realidad no está justificado revelar un RAW con un aumento de la exposición sino que lo veo más bien como un control de display para revelar más comodamente imágenes subexpuestas. Si no me he perdido ya probamos estas 3 estrategias:
0. Normal
1. Modelo Y CIE + curva con codo
2. Modelo Y HSV + curva con codo
2bis. Modelo Y HSV experimental (el que genera halos)

Pero lo probamos, tanto en su versión normal (daba posterizaciones) como experimental (daba halos):


Eso es. Yo me quedaría con la 1.

Así que nos quedamos con el modelo Y CIE y curvas con codo para exp<1 y rectas con codo para exp>1. Abajo pongo el código final.

Guillermo Luijk
25/05/2008, 21:21
El código final implementa un único modo de ajuste de exposición, pero existe un parámetro adicional (también en pasos de diafragma) que indica cuántos diafragmas de altas luces se preservarán en los aumentos y reducciones del valor de la exposición, es decir, cuántos diafragmas a contar desde la saturación no serán corregidos por el facto standard sino por una curva de preservación. Si este parámetro vale 0, el funcionamento será como era hasta ahora el modo 0, es decir, no se preserva nada y todos los niveles se multiplican por la corrección de exposición.

Así se requieren dos controles para definir la corrección de exposición:
Corrección de exposición: -8..0..+8
Diafragmas a preservar: 0..8El código final sería (en rojo nuevas variables):



void exposure_correction(void){
// variables de entrada desde formulario:
// exposure (lineal): 2^(-8..0..8)
// preserve (log): 0..8
int i;
float Y, Yp, exposure2, K, EV;

if(verbose) printf("Exposure correction ");
if(preserve==0.0){
// Exposure correction without highlight preservation
if(verbose) printf("without highlight preservation\n");
for(i=0;i<height*width;i++){
image[i][0]=CLIP((float)image[i][0]*exposure); // R
image[i][1]=CLIP((float)image[i][1]*exposure); // G (mixed)
image[i][2]=CLIP((float)image[i][2]*exposure); // B
}
}else{
// Exposure correction with highlight preservation
if(verbose) printf("with highlight preservation\n");
if(exposure>1){
K=65535/exposure*pow(2,-preserve);
for(i=0;i<height*width;i++){
Y=0.299*(float)image[i][0]+0.587*(float)image[i][1]+0.114*(float)image[i][2]; // CIE luminosity
if(Y<K){
image[i][0]=CLIP((float)image[i][0]*exposure); // R
image[i][1]=CLIP((float)image[i][1]*exposure); // G (mixed)
image[i][2]=CLIP((float)image[i][2]*exposure); // B
}else{
Yp=(65535-K*exposure)/(65535-K)*(Y-65535)+65535;
exposure2=Yp/Y;
image[i][0]=CLIP((float)image[i][0]*exposure2); // R
image[i][1]=CLIP((float)image[i][1]*exposure2); // G (mixed)
image[i][2]=CLIP((float)image[i][2]*exposure2); // B
}
}
}else{
EV=log(exposure)/log(2); // Convertimos exp. lineal a EV
K=pow(2,-preserve);
for(i=0;i<height*width;i++){
Y=0.299*(float)image[i][0]+0.587*(float)image[i][1]+0.114*(float)image[i][2]; // CIE luminosity
if(Y<K){
image[i][0]=CLIP((float)image[i][0]*exposure); // R
image[i][1]=CLIP((float)image[i][1]*exposure); // G (mixed)
image[i][2]=CLIP((float)image[i][2]*exposure); // B
}else{
exposure2=pow(2,EV*(1-Y/65535)/(1-K));
image[i][0]=CLIP((float)image[i][0]*exposure2); // R
image[i][1]=CLIP((float)image[i][1]*exposure2); // G (mixed)
image[i][2]=CLIP((float)image[i][2]*exposure2); // B
}
}
}
}
}
Creo que la solución final es muy buena porque la única manera que tenemos de alterar el tono de un píxel será saturando alguno de sus canales (nunca ocurrirá con f<=1), y esto lo vamos a poder chequear al milímetro en el aviso de altas luces quemadas.

ManuelLlorens
25/05/2008, 23:04
El código final sería (en rojo nuevas variables):

(...)


Genial, este mediodía lo pruebo. Por cierto, _GUI_, te contesté a un mensaje sobre el tema de cómo elegir el parámetro nuevo. ¿Lo has leído?

Un saludo:

Guillermo Luijk
26/05/2008, 13:34
Genial, este mediodía lo pruebo. Por cierto, _GUI_, te contesté a un mensaje sobre el tema de cómo elegir el parámetro nuevo. ¿Lo has leído?

Un saludo:

Hosti pues ni idea, era un MP? yo lo había planteado en forma de diafragmas, que es muy fotográfico, pero si tienes una idea mejor...

También tengo que contestar a lo del histograma gamma sí, gamma no, y tengo malas noticias (es imprescindible calcularlo sobre la imagen final, incluyendo conversión a perfil de color y compensación gamma).

ManuelLlorens
26/05/2008, 15:08
Hosti pues ni idea, era un MP? yo lo había planteado en forma de diafragmas, que es muy fotográfico, pero si tienes una idea mejor...
No, si la idea es la misma. Lo que decía es poner una especie de cuentagotas para indicar, bien sobre la vista, bien sobre el histograma, la zona en la que quieres establecer el parámetro. Y para el histograma, lo mismo para el punto de saturación y el punto negro. Así ya tienes hecha la calibración que querías.


También tengo que contestar a lo del histograma gamma sí, gamma no, y tengo malas noticias (es imprescindible calcularlo sobre la imagen final, incluyendo conversión a perfil de color y compensación gamma).
No hay ningún problema, sólo elegir bien. Te he contestado en el subforo del histograma.

Un saludo:

Guillermo Luijk
26/05/2008, 15:14
No, si la idea es la misma. Lo que decía es poner una especie de cuentagotas para indicar, bien sobre la vista, bien sobre el histograma, la zona en la que quieres establecer el parámetro.

Y para el histograma, lo mismo para el punto de saturación y el punto negro. Así ya tienes hecha la calibración que querías.

A lo primero OK, sería cojonudo porque es muy gráfico ver dónde está el volumen de información y hacer click en él. Ojo que hay que convertir hacia atrás por la gamma (porque el histograma normalmente será gamma). Es decir, que si ponemos el cuentagotas en el centro del histograma, no será un 'preserve' de 1 diafragma, sino bastantes más si el histograma es gamma.
De hecho al histograma aunque sea en gamma le voy a poner palitos que representen los diafragmas logarítmicos.

A lo segundo (negro y sat.) imposible, porque el histograma ya muestra esos puntos de negro y sat. corregidos:

El negro es sustraido y por tanto los niveles inferiores a él ajustados a 0 en scale_colors()
La sat. es ajustada a 65535 en scale_colors()


Por lo tanto en el histograma no se tiene noción de esos dos puntos que acaban ajustados a 0 y 65535. Sí tiene sentido usar el histograma con un grado de zoom 1:1 en el 0 y en 65535 (o donde termine el histograma RAW), para ver cómo ajustar el negro y la sat. afectan a la imagen.

Por cierto en el link de scale_colors() os preguntaba una dudilla del acceso al array de la imagen en C.

ManuelLlorens
26/05/2008, 15:36
A lo primero OK, sería cojonudo porque es muy gráfico ver dónde está el volumen de información y hacer click en él. Ojo que hay que convertir hacia atrás por la gamma (porque el histograma normalmente será gamma). Es decir, que si ponemos el cuentagotas en el centro del histograma, no será un 'preserve' de 1 diafragma, sino bastantes más si el histograma es gamma.

A lo segundo (negro y sat.) imposible, porque el histograma ya muestra esos puntos de negro y sat. corregidos:

Claro, es que yo decía tener la opción de ver un histograma lineal, sin gamma. Así puedes poner black=0, sat=65535, ver el histograma sin gamma, y elegir en él.


Por cierto en el link de scale_colors() os preguntaba una dudilla del acceso al array de la imagen en C.
Es verdad... uno recorre la imagen sin tener en cuenta el canal, el otro es un caso particular que es mejor que no estudies mucho porque recorre la imagen en celdas para calcular el WB. Hay otro modo de recorrerlo teniendo en cuenta el canal. Ya te pasaré todo cuando llegue el momento, pero es sencillo.

Aggg! me estoy quedando sin pilas en el teclado...

Un saludo:

Guillermo Luijk
27/05/2008, 01:29
Hay un bug en mi código para exp<1 Manuel, tema de escala (0..1 vs 0..65535). Con exp<1 y preservación de 1 diafragma se obtenía menos exposición que con exp<1 y sin preservación.

El código corregido (en azul los cambios):



void exposure_correction(void){
// variables de entrada desde formulario:
// exposure (lineal): 2^(-8..0..8)
// preserve (log): 0..12
int i;
float Y, Yp, exposure2, K, EV;

if(verbose) printf("Exposure correction ");
if(preserve==0.0){
// Exposure correction without highlight preservation
if(verbose) printf("without highlight preservation\n");
for(i=0;i<height*width;i++){
image[i][0]=CLIP((float)image[i][0]*exposure); // R
image[i][1]=CLIP((float)image[i][1]*exposure); // G (mixed)
image[i][2]=CLIP((float)image[i][2]*exposure); // B
}
}else{
// Exposure correction with highlight preservation
if(verbose) printf("with highlight preservation\n");
if(exposure>1){
K=65535/exposure*pow(2,-preserve);
for(i=0;i<height*width;i++){
Y=0.299*(float)image[i][0]+0.587*(float)image[i][1]+0.114*(float)image[i][2]; // CIE luminosity
if(Y<K){
image[i][0]=CLIP((float)image[i][0]*exposure); // R
image[i][1]=CLIP((float)image[i][1]*exposure); // G (mixed)
image[i][2]=CLIP((float)image[i][2]*exposure); // B
}else{
Yp=(65535-K*exposure)/(65535-K)*(Y-65535)+65535;
exposure2=Yp/Y;
image[i][0]=CLIP((float)image[i][0]*exposure2); // R
image[i][1]=CLIP((float)image[i][1]*exposure2); // G (mixed)
image[i][2]=CLIP((float)image[i][2]*exposure2); // B
}
}
}else{
EV=log(exposure)/log(2); // Convertimos exp. lineal a EV
K=65535*pow(2,-preserve);
for(i=0;i<height*width;i++){
Y=0.299*(float)image[i][0]+0.587*(float)image[i][1]+0.114*(float)image[i][2]; // CIE luminosity
if(Y<K){
image[i][0]=CLIP((float)image[i][0]*exposure); // R
image[i][1]=CLIP((float)image[i][1]*exposure); // G (mixed)
image[i][2]=CLIP((float)image[i][2]*exposure); // B
}else{
exposure2=pow(2,EV*(65535-Y)/(65535-K));
image[i][0]=CLIP((float)image[i][0]*exposure2); // R
image[i][1]=CLIP((float)image[i][1]*exposure2); // G (mixed)
image[i][2]=CLIP((float)image[i][2]*exposure2); // B
}
}
}
}
}

ManuelLlorens
27/05/2008, 09:28
Ok, ya lo he puesto. Voy a subir otra prueba.

Guillermo Luijk
29/05/2008, 04:19
Idea: para Manuel que no ve intuitiva la relación entre las cifras de corrección de ajuste de exp. y diafragmas preservados, no cuesta nada dibujar a voluntad sobre el histograma la curva que representa el ajuste de exp./preserv. que se ha aplicado.

Por supuesto hay que entender que no es una curva RGB sino que se aplica sobre la luminosidad, pero el concepto está claro. También hay que entender que dicha curva afecta al histograma, y el histograma sobre el que se está superponiendo es el histograma resultante de aplicar (entre otras cosas) esa curva, cuando lo intuitivo y/o más habitual es ver las curvas sobre el histograma origen.

ManuelLlorens
29/05/2008, 12:19
Idea: para Manuel que no ve intuitiva la relación entre las cifras de corrección de ajuste de exp. y diafragmas preservados, no cuesta nada dibujar a voluntad sobre el histograma la curva que representa el ajuste de exp./preserv. que se ha aplicado.

Por supuesto hay que entender que no es una curva RGB sino que se aplica sobre la luminosidad, pero el concepto está claro. También hay que entender que dicha curva afecta al histograma, y el histograma sobre el que se está superponiendo es el histograma resultante de aplicar (entre otras cosas) esa curva, cuando lo intuitivo y/o más habitual es ver las curvas sobre el histograma origen.
Es una gran idea. Creo que sería interesante sacar un histograma, sólo eso el histograma no el buffer completo, justo antes de aplicar la recuperación de altas luces. Ahí tenemos un buffer y no tenemos más que pedir que se calcule el histograma y tenerlo guardado. Podemos llamarlo histograma RAW. Sería interesante para ver cómo afectan al histograma la recuperación de altas luces, la exposición, el espacio de color de salida y la gamma de salida. Creo que esté tirado de implementar.

Un saludo: