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..8
El código final sería (en rojo nuevas variables):
Código:
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.
Marcadores