Manuel:
el algoritmo de marcado que proponía GUI sería algo así:
Como ves, no he comprobado si flash es > 0, pues con lo propuesto por GUI no hay tres estados posibles, sólo dos: o dejar la imagen con su valor de pixels inalterado (en uno de los ticks del reloj) o marcar el quemado (en otro tick).Código:inline void PixelFrom16to8(PX8 *data8,PX16 *data16, int flash) { if(flash){ if( data16[0]== 65535 ) data8[0]=128; else data8[0]= data16[0]>>8; if( data16[1]== 65535 ) data8[1]=128; else data8[1]= data16[1]>>8; if( data16[2]== 65535 ) data8[2]=128; else data8[2]= data16[2]>>8; } else { data8[0]= data16[0]>>8; data8[1]= data16[1]>>8; data8[2]= data16[2]>>8; } }
El comparar si es distinto de cero es ligeramente más rápido que comparar si es positivo.
Se podría ahorrar un poquito más (aunque sería marginal) evitando la comprobación de la variable flash por cada pixel recorrido, separando las rutinas FastDraw en dos: una implenmentando el marcado de pixels con la primera parte del if y otra sin el marcado de pixels con la parte del else en su lugar.
Otra mejora estaría en comprobar no si es igual a 65535 sino hacer un xor (o exclusivo) bit a bit con 0xFFFF que es más rápido.
Esto dará distinto de cero si no es igual y sólo dara 0 (0x0000) si el valor es igual a 0xFFFF.
Esto sí creo que pueda merecer la pena cambiarlo porque en vez de hacer una resta en cada operación para ver si le sale nulo, es suficiente con un xor que es mucho más rápido. Aunque es posible que un compilador moderno haga esa optimización del código él solito.
Un incremento de velocidad marginal serí utilizar operadores de desplasamiento de punteros ++data, aunque quedará mucho menos legible.Código:if( data16[0] ^ 0xFFFF ) data8[0] = data16[0]>>8; else data8[0]= =128;
Además seguramente con los compiladores actuales y sus optimizaciones esta optimización ya la haga el compilador.
Quedaría algo así (edito: lo corrijo porque estaba mal escrito):
Creo no haberme equivodado al poner la lógica de punteros. Habrá que comprobarlo.Código:inline void PixelFrom16to8(PX8 *data8,PX16 *data16, int flash) { if(flash){ if( (*data16) ^ 0xFFFF ) *(data8++) = (*(data16++))>>8; else *(data8++) =128; if( (*data16) ^ 0xFFFF ) *(data8++) = (*(data16++))>>8; else *(data8++) =128; if( (*data16) ^ 0xFFFF ) *(data8++) = (*(data16++))>>8; else *(data8++) =128; } else { *(data8++) =128; *(data8++) =128; *(data8++) =128; } }
Última edición por ariznaf; 19/05/2008 a las 18:37 Razón: Corrección de errores en el código del último ejemplo.
¿Debería funcionar en Windows Vista?
Saludos, Angel
Tengo mi propia del versión del optimismo.
Si no puedo cruzar una puerta, cruzaré otra o haré otra puerta.
Algo maravilloso vendrá, no importa lo oscuro que esté el presente.
En Vista sí, en Vista 64 no (aunque esperábamos que funcionara no ha sido así, aunque estamos en ello e intentaremos que así sea, por la cuenta que me tiene, que yo uso Vista 64).
En el 64 te funcionarán los test que puso Manuel del entorno con el jpeg del salón, pero no el test de revelado.
El problema está en que la dll de dcraw no funciona en Vista 64.
Estamos en ello, pero hay otras prioridades (aunque en el momento que esto avance un poco y se integre revelador y entorno, yo voy a necesitar hacer algo, porque dejará de funcionarme la aplicación)![]()
Sí, hay varias optimizaciones que pensaba hacer sobre el código final, pero iré poniéndolas todas ahora.
Eso lo pierdes en facilidad de mantenimiento del código, creo que no merecerá la pena, pero lo estudiaré.
¿Tenemos claro que saturado significa exactamente igual a 0xFFFF? ¿No vamos a querer definir un umbral más abierto? Si es así lo optimizaremos como tú dices, claro. Y lo mismo en 0.
Eso efectivamente ya lo optimiza el compilador. *(data+5) y data[5] se convierte en lo mismo una vez en ensamblador.
Voy a subir la prueba a 16 bits, esta noche te pasaré el código para que lo cambies en tu clase vista.
Un saludo:
_________________________________
Aquí va la prueba del GUI a 16 bits con el diseño de ariznaf. Parpadean los blancos a negro y los negros a blanco. Las dos vistas van a 16 bits. El rar pesa mucho más porque lleva dentro un TIFF de 16 bits, claro. Además tarda al arrancar porque .NET tarda un montón en cargar un TIFF y porque hace un cálculo de gamma sRGB cutre en código 100% .NET, cuando tire del revelado no tendrá ese retardo en arrancar.
He arreglado el botón 2 para que podáis comparar velocidades. (Le quedan al FTP 10 minutos para terminar de subirlo, tened paciencia).
http://www.ojodigital.com/prawpblender/GUI16.rar
Un saludo:
Última edición por ManuelLlorens; 19/05/2008 a las 18:20 Razón: Fusión automática de mensajes para prevenir autosubir post
Bueno, eso lo planteó GUI en este mismo hilo y yo creo que tiene razón: quemados son quemados, con el valor más alto posible. Con un umbral no serían quemados sino "altos", pero recuperables con ajustes de exposición. Sólo querríamos marcar los "irrecuperables".¿Tenemos claro que saturado significa exactamente igual a 0xFFFF? ¿No vamos a querer definir un umbral más abierto? Si es así lo optimizaremos como tú dices, claro. Y lo mismo en 0.
Si pero si hay tres instrucciones seguidas como:Eso efectivamente ya lo optimiza el compilador. *(data+5) y data[5] se convierte en lo mismo una vez en ensamblador.
data[0]= xxx;
data[1]= xxx;
data[2]=xxx;
no sé si el compilador detecta que los índices son seguidos o lo convierte en:
*(data)=xxx;
*(data+1)=xxx;
*(data+2)=xxx;
En vez de en:
*(data++)=xxx;
*(data++)=xxx;
*(data++)=xxx;
Los procesadore tienen operaciones especiales de incremento en uno de un puntero más rápidas y sin acceso a memoria (en un solo ciclo) que llevará menos que el sumar una constante de desplazamiento (que requiere hacer la suma y cargar el valor a sumar, lo que es más de un ciclo).
Por cierto que en el ejemplo anterior estaba mal puesto y había puest ++(*data) que lo que haría sería incrementar en uno el valor almacenado y no el puntero.
Lo corregiré.
_________________________________
MMMM a ver Manuel: más compacto todavía usando el operador ternario (que dicen que está optimizado por el compilador y hace menos saltos que el if ... else.
Es posible que haya algún error pero compilar compilaCódigo:inline void PixelFrom16to8(PX8 *data8,PX16 *data16, int flash) { if(flash){ *(data8++)= ( (*data16) ^ 0xFFFF ) ? (*(data16++))>>8 : 128; *(data8++)= ( (*data16) ^ 0xFFFF ) ? (*(data16++))>>8 : 128; *(data8++)= ( (*data16) ^ 0xFFFF ) ? (*(data16++))>>8 : 128; } else { *(data8++) =128; *(data8++) =128; *(data8++) =128; } }
_________________________________
Por cierto, Manuel:
ya que a mi no me funciona el revelador en Vista 64 y hasta que esto se arregle, ¿podrías seguir haciendo las pruebas con el test y cargando un tiff de 16 bits en vez de un jpeg de 8?
De esta manera podríamos seguir avanzando con el tema de la interface gráfica, prescindiendo temporalmente del problema del revelador dcraw.
Última edición por ariznaf; 19/05/2008 a las 18:58 Razón: Fusión automática de mensajes para prevenir autosubir post
A ver que esto no es lo que decía, sino:
No sé si estáis creandos dos bitmaps que se alternan según el reloj del parpadeo, pero la idea es ésta: cuando parpadean las zonas quemadas, en los píxels quemados no aparece NADA que tenga que ver con la imagen original, sale sólo un color que nos informa acerca de los canales que están quemados. Y cuando no parpadean aparece la imagen original (con sus quemados sin los tiene claro).Código:if(flash){ // Imagen parpadeo if( data16[0]== 65535 or data16[1]== 65535 or data16[2]== 65535 ) // El píxel tiene algún canal quemado { if( data16[0]== 65535 ) data8[0]=128; else data8[0]= 0; if( data16[1]== 65535 ) data8[1]=128; else data8[1]= 0; if( data16[2]== 65535 ) data8[2]=128; else data8[2]= 0; if data8[0]=128 and data8[1]=128 and data8[2]=128 { data8[0]=0; data8[1]=0; data8[2]=0; } } else { // El píxel no tiene ningún canal quemado data8[0]= data16[0]>>8; data8[1]= data16[1]>>8; data8[2]= data16[2]>>8; } } else { // Imagen normal data8[0]= data16[0]>>8; data8[1]= data16[1]>>8; data8[2]= data16[2]>>8; }
Respecto a poner umbrales, quizá si que es mejor poder poner un umbral, es decir, que quemado sea mayor de 65536-50 por ejemplo, porque a veces ocurre que el punto de saturación de las cámaras oscila y da lugar a saturaciones en valores algo por debajo de 65536.
"En ocasiones veo halos."
http://www.guillermoluijk.com para suscribirte haz clic aquí
Último contenido: PARA QUÉ SIRVE EL RANGO DINÁMICO?
No, no se están creando dos bitmap, sino uno sólo, por eso en los no quemados copio el valor del pixel original.
Lo que tú propones sería un método de máscara: marcar en otro buffer los pixels quemados con algo distinto de 0.
Para eso sobraría la parte del else que establece los valores en 0, pues el buffer se inicializaría todo el a 0 con un memset de una sola vez (más rápido).
En el parpadeo se vuelve a hacer el reescalado y demás de cada vez: una con pixels quemados y otra sin ellos.
Por ahora funciona bastante rápido y bien. Si esto lo ralentiza, habría que utilizar la técnica de double buffer, pero yo siempre prepararía una imagen definitiva, sino habría que montar la máscara de pixels quemados sobre la imagen al final y eso en GDI+ es lent o según en comparación con el algoritmo de manuel (las operaciones con bitmaps en GDI son lentas por las pruebas que hizo al principio Manuel).
Si se quieren poner umbrales habrá que volver a lo de la comparación con un valor mínimo:
*(data8++)= ( (*data16) >= umbral ) ? (*(data16++))>>8 : 128;
en vez de:
*(data8++)= ( (*data16) ^ 0xFFFF ) ? (*(data16++))>>8 : 128;
El umbral debería de dejarse como un valor configurable que se pase a la función o una variable global de la dll para poder ajustarlo (aunque esto será más lento que utilizar un valor constante, pues requiere un acceso a memoria más).
Si no se piensa que el usuario vaya a andar cambiándolo, se puede definir con un const en la dll de fastdraw.
editado para probar superpoderes
Última edición por Guillermo Luijk; 20/05/2008 a las 00:42
A ver, o yo estoy entendiendo mal esto:
o tú lo que haces es: si un canal está quemado, lo pones a 128, y si no está quemado, lo dejas como era en origen. Si eso es así, está mal. Eso va a formar en las zonas parcialmenet quemadas un color que no se sabrá lo que es, porque vendrá dado por una mezcla de canales quemados a 128, y canales de la imagen original, no?Código:if( data16[0]== 65535 ) data8[0]=128; else data8[0]= data16[0]>>8; if( data16[1]== 65535 ) data8[1]=128; else data8[1]= data16[1]>>8; if( data16[2]== 65535 ) data8[2]=128; else data8[2]= data16[2]>>8;
Por eso te decía que en la imagen que se ha de mostrar cuando estén parpadeando las luces quemadas, se haga:
Así si se quema solo el canal rojo, verde o azul, parpadeará en dicho color. Si se quema R+G parpadeará en amarillo (B=0), si se quema R+B parpadeará en magenta (G=0), si se queman los 3, los ponemos a 0 (negro) para que se distinga mejor aún.Código:if( data16[0]== 65535 ) data8[0]=128; else data8[0]= 0; if( data16[1]== 65535 ) data8[1]=128; else data8[1]= 0; if( data16[2]== 65535 ) data8[2]=128; else data8[2]= 0; if data8[0]=128 and data8[1]=128 and data8[2]=128 then { data8[0]=0; data8[1]=0; data8[2]=0}
Se trata de construir los colores para lograr estos chivatos (los de la izq.) en las 7 posibles combinaciones de saturaciones:
Última edición por Guillermo Luijk; 19/05/2008 a las 20:32
"En ocasiones veo halos."
http://www.guillermoluijk.com para suscribirte haz clic aquí
Último contenido: PARA QUÉ SIRVE EL RANGO DINÁMICO?
Vale, no lo había leído bien... entonces OK.
Es que no son lo mismo. Tu segundo ejemplo modifica el puntero, el primero es una operación de búsqueda en tabla que no modifica el puntero, no es lo mismo: data++ es lo mismo que data=data+1, no que data+1 a secas.
_________________________________
Te veo emocionado con el C... no te preocupes que lo optimizaremos bien. Había pensado en evitar el if utilizando un puntero a la función, pero entonces no podríamos usar el inline. Creo que meteré el if dentro de la función que la llama para optimizar y a la vez mantener el código lo mejor posible.
_________________________________
Eso hago en el ejemplo que acabo de subir. Si subo ejemplos subsiguientes no volverá a subir el tiff para no cargar el download. En cuanto retoque un poco el código te lo paso para que lo juntes con el tuyo.
Un saludo:
_________________________________
Bueno, no os preocupéis demasiado por el código del parpadeo. Yo me encargo de que funcione como quiere _GUI_ y tan optimizado como se posible para contentar a ariznaf. Esta noche subo el ejemplo. Por cierto, en el código que he subido fuerzo la imagen para que se queme y parpadee. Buscaré una nueva imagen con más "paleta de colores", a ver si consigo una que tenga realmente quemados píxeles de diversos canales.
Última edición por ManuelLlorens; 19/05/2008 a las 20:40 Razón: Fusión automática de mensajes para prevenir autosubir post
Manuel:
Es que no son lo mismo. Tu segundo ejemplo modifica el puntero, el primero es una operación de búsqueda en tabla que no modifica el puntero, no es lo mismo: data++ es lo mismo que data=data+1, no que data+1 a secas.
Hombre claro, ahí está la gracia no... precisamente lo que hace es obtener el valor de la posición actual del puntero y después mover el puntero a la siguiente posición, quedando apuntanto a donde tenemos almacenado el siguiente canal de color.
Luego vuelve a repetir lo mismo con el siguiente canal. Al final el puntero queda apuntando al primer canal del siguiente pixel.
Esa es precisamente la gracia.
Sólo se puede hacer esto cuando no necesitamos volver a acceder a la posición antigua (sólo se accede una vez) y cuando los valores a acceder son seguidos como en este caso.
GUI:
Ahora el que no entiende nada soy yo.A ver, o yo estoy entendiendo mal esto:
Código:
.............. eliminado .........
o tú lo que haces es: si un canal está quemado, lo pones a 128, y si no está quemado, lo dejas como era en origen. Si eso es así, está mal. Eso va a formar en las zonas parcialmenet quemadas un color que no se sabrá lo que es, porque vendrá dado por una mezcla de canales quemados a 128, y canales de la imagen original, no?
Por eso te decía que en la imagen que se ha de mostrar cuando estén parpadeando las luces quemadas, se haga:
Código:
........... eliminado .........
Así si se quema solo el canal rojo, verde o azul, parpadeará en dicho color. Si se quema R+G parpadeará en amarillo (B=0), si se quema R+B parpadeará en magenta (G=0), si se queman los 3, los ponemos a 0 (negro) para que se distinga mejor aún.
El parpadeo no se hace con dos buffers, sino creando en una ocasión la imagen tal cuál sin marcar pixels quemados y en la siguiente marcándolos.
En el código que tú pones lo que haces es poner a 128 los canales quemados y a 0 los que no lo están. Pero entonces obtendremos una imagen con todo en negro menos los pixels con los canales quemados.
Si te endiendo bien lo que pretendes es que en vez de dejar los otros canales como estaban, los pongamos con valor 0, de forma que el color sea un rojo neutro si se quema el color rojo, etc.
Pero el código entonces sería así:
Tampoco es exactamente eso, pues tal y como está sólo contempla el que se queme un canal, no dos o tres.Código://copiar primero los valores del pixel convertidos a 8 bits. data8[0] = data16[0] >> 8; data8[0] = data16[0] >> 8; data8[0] = data16[0] >> 8; //Si está quemado el canal rojo, poner un rojo medio if( data16[0]== 65535 ) { data8[0]=128; data8[1]=0; data8[2]=0; } else data8[0]= 0; //Si está quemado el verde, un verde medio. if( data16[1]== 65535 ) { data8[0]=0; data8[1]=128; data8[2]=0; } else data8[1]= 0; //Si está quemado el azul, un azul medio. if( data16[2]== 65535 ) { data8[0]=0; data8[1]=0; data8[2]=128; }
Ya pensaré algo para ver cómo resolver las posibles combinaciones de que se queme más de un canal (evitando poner muchos ifs) y lo pongo.
Última edición por ariznaf; 19/05/2008 a las 21:16
A ver, que te estás liando con los dedos de los pies, y es sencillísimo, ya lo había puesto antes. A ver:
Código:if(flash){ // Imagen parpadeo if( data16[0]== 65535 or data16[1]== 65535 or data16[2]== 65535 ) // El píxel tiene algún canal quemado { if( data16[0]== 65535 ) data8[0]=128; else data8[0]= 0; if( data16[1]== 65535 ) data8[1]=128; else data8[1]= 0; if( data16[2]== 65535 ) data8[2]=128; else data8[2]= 0; if data8[0]=128 and data8[1]=128 and data8[2]=128 { data8[0]=0; data8[1]=0; data8[2]=0; } } else { // El píxel no tiene ningún canal quemado data8[0]= data16[0]>>8; data8[1]= data16[1]>>8; data8[2]= data16[2]>>8; } } else { // Imagen normal data8[0]= data16[0]>>8; data8[1]= data16[1]>>8; data8[2]= data16[2]>>8; }
Si no flash dejamos la imagen original tal cual en todos los pixels.
Si flash, generamos la imagen parpadeo:
- Si el píxel tiene algún canal quemado, se generan las 7 combinaciones de color posibles (donde no interviene para nada el valor de los canales no quemados del píxel).
- Si el píxel no tiene ningún canal quemado, se dejan los canales originales.
Yo no sé muy bien si la implementación la hacéis con 2 buffers o uno solo que se reescribe, pero la idea es ésta. Por cierto, pensáis que es óptimo (tiempo de procesado) estar recalculando a cada parpadeo toda la imagen en lugar de tener 2 buffers de 8 bits?
Última edición por Guillermo Luijk; 19/05/2008 a las 21:28
"En ocasiones veo halos."
http://www.guillermoluijk.com para suscribirte haz clic aquí
Último contenido: PARA QUÉ SIRVE EL RANGO DINÁMICO?
A ver creo que ya lo tengo:
La siguiente tabla con las posibles combinaciones de valores quemados y los colores que se quieren asignar:
Obsérvese que la representación binaria del índice de entrada de la tabla coincide con los canales quemados (entendiendo por 1 canal correspondiente quemado y 0 no quemado)Código:Indice | Rojo | Verde | Azul | Color a asignar 0 0 0 0 El original del pixel. 1 0 0 1 RGB=(0,0,128) 2 0 1 0 RGB=(0,128,0) 3 0 1 1 RGB=(0,128,128) 4 1 0 0 RGB=(128,0,0) 5 1 0 1 RGB=(128,0,128) 6 1 1 0 RGB=(128,128,0) 7 1 1 1 RGB=(128,128,128)
Por consiguiente sólo haría falta generar el índice comprobando qué canal está quemado con operaciones lógicas y de desplazamiento de bits y luego entrar en la tabla para obtener el valor a asignar.
Con ello se ahorran comprobaciones u operaciones aritméticas.
El código quedaría algo así:
Si como dices quieres que cuando los tres canales estén quemados en vez de un gris RGB=(128,128,128) sea un negro RGB=(0,0,0) es suficiente con cambiar las entradas de la tabla, poniendo en el último valor de cada color un 0 en vez de un 128.Código:typedef unsigned char PX8; typedef unsigned short PX16; const PX16 umbral =65500; const PX8 tablaR[8]= {0,0,0,0,128,128,128,128}; const PX8 tablaG[8]= {0,0,128,128,0,0,128,128}; const PX8 tablaB[8]= {0,128,0,128,0,128,0,128}; inline void PixelFrom16to8(PX8 *data8,PX16 *data16, int flash) { int indice; if(flash) { //construir el indice de entrada en la tabla a partir de los canales quemados indice = (data16[0]>=umbral); indice <<=1; indice |= (data16[1]>=umbral); indice <<=1; indice= (data16[2]>=umbral); if( indice ) { //indice != 0 significa canales quemados. Cambiar el color por los de la tabla data8[0]= tablaR[indice]; data8[1]= tablaR[indice]; data8[2]= tablaR[indice]; return; } } //Si hemos llegado hasta aquí o no se marcan los canales quemados (flash =0) // o no hay ninguno quemado. data8[0]= data16[0]>>8; data8[1]= data16[1]>>8; data8[2]= data16[2]>>8; }
En realidad con esa tabla se podría asignar los colores que quisiéramos a cada combinación de canales quemados.
Vaya, nos hemos cruzado.
Bien ahora que repaso el código completo lo entiendo.
Sí que había entendido bien lo que querías hacer (ahora que antes creí que los otros canales no quemados había que dejarlos como estaban).
Lo que pasa que en la última vez que lo pusiste no habías puesto todo el código (faltaba el if del principio).
Mi alternativa es similar sólo que sin todas las comparaciones. Únicamente tres y algunos desplazamientos de bits, por lo que creo que será más rápida.
Será cuestión de probar.
jeje ya te digo que yo transmito solo ideas. tómate lo que pongo al 100% como pseudocódigo, a implementar y optimizar como consideréis mejor.
Lo del umbral está bien porque muchas veces (en general por fallo del punto de saturación de DCRAW) hay RAWs que saturan a 65534 o unos pocos niveles menos. Son saturaciones con todas las de la ley, pero por culpa del punto de saturación no llegan a 65535. De hecho no vería mal un slider para controlar dicho umbral.
"En ocasiones veo halos."
http://www.guillermoluijk.com para suscribirte haz clic aquí
Último contenido: PARA QUÉ SIRVE EL RANGO DINÁMICO?
Vaya, ariznaf, estamos haciendo los dos lo mismo:
Un saludo:Código:mask=(data16[0]<=uH)+(data16[1]<=uH)<<1+(data16[2]<=uH)<<2+(data16[0]>=uL)<<3+(data16[1]>=uL)<<4+(data16[2]>=uL)<<5; if(mask!=0){ data8[0]=ColorMask[mask][0]; data8[1]=ColorMask[mask][1]; data8[2]=ColorMask[mask][2]; }else{ data8[0]=(data16[0]>>8); data8[1]=(data16[1]>>8); data8[2]=(data16[2]>>8); }
He implementado el control de exposición en esta función, que es prácticamente el código puesto por _GUI_:
Entiendo que el modo de preservación de luces sólo tiene sentido para valores de f>1.0, ¿verdad _GUI_? Por eso he añadido una condición en ese sentido en el if inicial.Código:void exposure_correction(void){ int i; float Y, Yp, exposure2, K1, K2; if(verbose) printf("Exposure correction "); if((exposure_mode==0)||(exposure<1.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"); K1=32768/exposure; K2=65535-K1; 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<K1){ 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=32767*(Y-65535)/K2+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 } } } }
He actualizado el revelador para que puedas probarlo. Utiliza una gamma lenta por lo que es un poco rollazo de probar (no sé porqué, pero mi LUT en MinGW es bastante lenta, si hubiese puesto una LUT superrápida como la que pienso poner todo el proceso duraría menos de un segundo), pero vale para que veas el efecto del control de exposición que has propuesto. No hay slider, pero sí un control up/down que va de 0,25 en 0,25. Más adelante podemos poner uno tipo cámara: 0,3 - 0,7 - 1... de momento para probar vale así. También hay un checkbox para seleccionar la preservación de luces altas.
A mí personalmente me parece bastante correcto, incluso espectacular preservando luces altas.
Enlace al nuevo revelador (aún no funcionará en Vista 64y he machacado la prueba del revelador anterior).
¡OJO! para que funcione esta prueba debe existir el archivo c:\test\1_a.dng (y ser un DNG válido, obviamente). Al mediodía de hoy subiré una versión sin esa limitación. Disculpad.
Un saludo:
Última edición por ManuelLlorens; 20/05/2008 a las 11:07
No tiu, con f<1.0 también es interesante tener preservación de altas luces (a elección del usuario siempre eh?), explico porqué:
- Si una imagen no tiene nada quemado, entonces sí, es tontería aplicar esta preservación (que luego cuento en qué consiste), lo correcto y lo que se habría obtenido con la cámara caso de exponer menos es: R'=R*f...
- Pero si una imagen tiene altas luces quemadas, típicamente a tope (R=G=B=255) o sea blancos, aplicar una exposición a la baja implica convertirlos en grises, cuando lo más lógico es pensar que esas altas luces estaban bastantes diafragmas por encima (es decir, no eran áreas que resultaron en un valor 65535, sino que habrían obtenido un valor mucho mayor, solo que saturaron a 65535), y por lo tanto es bueno que sigan siendo altas luces blancas para emular mejor el resultado que habríamos obtenido en la cámara caso de exponer menos.
Éste es precisamente el motivo por el que no suelo corregir la exposición (tanto al alza como a la baja) de los revelados procedentes de DCRAW con curvas en lineal (PS no admite curvas a tramos rectos como éstas), sino que aplico gamma y uso curvas normales; pero éstas ya alteran tono y saturación, no son verdaderos controles de exposición como el de la cámara.
Por eso planteé la curva azul: lo que está en negrita es una recta que pasa por (32768, 32768*f) y (65535, 65535), que se implementa con:
Por cierto, clip no redondea a enteros? por qué no haces clipf en este punto? es para ganar velocidad mientras se prueba?Código:else { // f<1 // Aplicar a toda la imagen bucle: Y = 0.299R + 0.587*G + 0.114*B // Calculamos luminosidad CIE if Y <= 32768 { R' = clipf(R * f) G' = clipf(G * f) B' = clipf(B * f) } else { Y' = (65535 - 32768*f) * (Y - 65535) / 32767 + 65535 f2 = Y' / Y R' = clipf(R * f2) G' = clipf(G * f2) B' = clipf(B * f2) } }
Esa curva tiene además una propiedad que no tiene la curva roja, y es que al ser f<1 sí que se va a garantizar la igualdad de tono en absolutamente todos los casos(estás trabajando en lineal no?). Prueba ese algoritmo con alguna imagen lineal con zonas de altas luces quemadas, y compara el aspecto de éstas cuando bajas la exposición comparado con el modo normal.
No me funciona (Vista 32 bits) el último Perfect RAW.exe, pero bueno da igual centraos en seguir adelante. Me siento aquí un poco como un ogro dandoos instrucciones de lo que hacer, pero es que estoy a años luz de vosotros, no soy capaz de hacer funcional el entorno de programación así que creo que ayudo más así.
jeje, os habéis dado cuenta de que podemos editarnos los posts entre nosotros? o sea, aunque no sean nuestros.
Última edición por Guillermo Luijk; 20/05/2008 a las 02:50
"En ocasiones veo halos."
http://www.guillermoluijk.com para suscribirte haz clic aquí
Último contenido: PARA QUÉ SIRVE EL RANGO DINÁMICO?
Es verdad, es que hice pruebas con una imagen y no vi diferencia, aunque intuía algo... debí seguir mi intuición y probar con una imagen más quemada. Lo cambio este mediodia. Miraré también lo del CLIP/CLIPF.
Estoy de acuerdo en que no te instales el entorno de programación, creo que no te merece la pena. Creo que ahora estamos funcionando bien, tú pones pseudocódigo (aunque cada vez es más C, la verdad) y ariznaf y yo lo implementamos. Luego colgamos un ejecutable para que lo pruebes y ponemos en el foro el código que hemos implementado para que lo revises, ¿_GUI_, ariznaf, os parece correcta esta forma de trabajo?
<_GUI_>: a mí sí, aunque sigo sin poder ejecutar nada. En el PC del curro (XP Pro) me pide que instale el .NET Framework. Pero vamos que da igual, con que me funcione al final de todo...
(por ariznaf)
Me parece bien, pero lo que no sé es si daré a basto para hacer mis cosas. GUI y tú sois una máquina de generar ideas.
Yo luego soy más bien lentito (sobre todo por que hace mucho que no programo y el .NET ha cambiado bastante).
Eso puede ser el caos. Supongo que los duendes que nos protegen van haciendo de las suyas. Se nota también en los subforos que han aparecido por arte de magia.
(por ariznaf)
Como expliqué más abajo lo he pedido yo. No todos pueden editar los mensajes sólo los que somos moderadores, que no nos dedicaremos a hacer el burro o jugar con lo de los demás ¿verdad?
___________________________________
He pensado en un nuevo reparto de tareas.
Os rogaría a los implicados que comentárais y/o confirmárais que el reparto es el adecuado. Por supuesto, no quiero imponer nada a nadie, sólo organizar un poco el tema para que no nos pisemos unos a otros. Dado que podemos editarnos los mensajes unos a otros. Sería bueno que en vez de contestar los que podáis editéis esta parte del mensaje y así queda algo definitivo.Sería bueno que apareciera dsamper, creo que nos ayudaría mucho.
- _GUI_ se pone a definir el balance de blancos: relación temperatura de color -> multiplicadores (te pasé algunos enlaces que ya tenías, pero me molesté en sacarte el código fuente para que no tengas que descargarte, por ejemplo, el SDK del DNG).
- He traspasado a ariznaf todo la maqueta del GUI. Así irá creciendo su clase de vistas con todo lo que llevamos hecho. Es mejor que un solo programador se encargue de esa tarea y ariznaf tiene las ideas muy claras al respecto. (por ariznaf) de acuerdo lo iré implementando según pueda. Una manita no vendría mal... para implementar alguna cosa concreta y separada de lo que yo pueda estar haciendo.
- Yo me sigo encargando del revelador, empezando por la dll de dcraw, terminaré (algún día) de arreglar sus bugs (sólo queda uno y lo tengo acorralado, es cuestión de horas que se entrege con las manos en alto, cuando salga le cortaré la cabeza y sólo quedará un imortal, que seré yo... lo siento, se me ha ido la pinza
). Revisaré el control de exposición como pongo arriba. Prepararé la dll para perfectBLEND. Iré integrando la clase de vistas de ariznaf (tirando de lo que suba a SVN) con el revelador y poniendo los controles que faltan (es decir, todos
).
- Otros temas (disculpad que ponga al burro delante):
- Yo empezaré a bucear en el SDK del DNG, al menos a ver si consigo aclararme de cuánto código hace falta para escribir un DNG sencillo y si podemos prescindir del SDK o al menos encapsularlo en una clase C#. Creo que conseguiré escribir un DNG partiendo de cero, que es lo verdaderamente importante para perfectBLEND. (por ariznaf) venga a ver si lo consigues. Estaría muy bien.
- Yo también revisaré cuando tenga dcraw.dll terminada si consigo hacerla funcionar con VC++.
- Y por último yo empezaré a diseñar controles personalizados con la esperanza de traspasárselos a ariznaf cuando él termine lo que está haciendo ahora.
- ariznaf seguirá con las pruebas en Vista 64. La pista de truji de los manifiestos es buena y hay que avanzar por ahí. Además él es el primer interesado
. (por ariznaf) A ver si se consigue. El problema está principalmente en dcrawDLL que es un hueso duro de roer. Lo que programemos nosotros no creo que haya mayor problema (incluso para pasarlo a 64 bits), sólo es cuestión de tener un poco de cuidado y ya lo hemos tenido encuenta declarando tipos como PX8 y PX16.
- _GUI_ seguirá pensando en perfectBLEND y también estaría bien que fuera definiendo los histogramas de perfectRAW.
<_GUI_>: necesito que me digáis el nombre de las variables con que se acceden a los 3 canales de la imagen, y el formato en que están, e implemento los histogramas lineal y logarítmico. Sería casi imprescindible que la ventana final dedicada al histograma tenga un ancho potencia de 2 (512 píxels vendría fenomanal).
Lo de Perfect BLEND las ideas las tengo clarísimas, es un programa muy sencillo y si encima no habrá que hacer balance de blancos más fácil aún. Lo duro va a ser lo del DNG.
De momento crearé un histograma con un int[65535] a lo bruto y otro con int[512] para visualizar rápido, que obviamente calcularé a partir del anterior. Creo que integrar la funcionalidad completa, en otra ventana, de histogrammar sería una buena idea, daría un fondo técnico al revelador que no hay en otros reveladores. Por cierto, tanto nuestro revelador como dcraw internamente usan int para los índices sobre el array de la imagen, así que el día que nuestras cámaras den imágenes de 65536x65536 píxeles el programa nos dejará de funcionar.
- vertex y perroverd seguirán haciendo pruebas en linux y mantiendo el SVN a punto.
- Los demás seguís probando lo que subamos (es decir, haciendo el prealfa-testing
).
Y creo que no me dejo nada.
___________________________________
Posibilidad de vernos las caras
Hablamos ariznaf y yo este fin de semana de vernos las caras el próximo lunes 16 de junio a las 18:00-19:00 horas en algún sitio donde podamos hablar y tomar algo. Tiene que ser en esa fechar porque él vendrá de Oviedo a Madrid y, como es listo, no lo hace habitualmente.
<Manuel>: ¿Cambiamos la hora de 19:30 a 22:00 y que se vaya uniendo el que pueda?
(por ariznaf)está bien ir de vez en cuando pero es como el vino: en grandes cantidades no sienta bien.
<_GUI_>: Yo los lunes a esas horas estoy currando en Pozuelo, un poco jodido lo tengo. Un finde podría ir a tu casa Manuel, y me enseñas a compilar (puedo probar el sillón relax?)
<Manuel>: es de cartón piedra, como los tanques de los iraquíes... si cuidas a los niños mientras yo programo luego te dejo darte un masaje.
Evidentemente podemos hacer otras quedadas parciales en las que no esté él e ir a esta todos los que podamos. Yo iré seguro a tomarme algo con ariznaf y el que se apunte.
Con franqueza me gustaría que pudiérais estar al menos los que aparecéis en el reparto de tareas de arriba y cualquier otro que se apunte, aunque algunos no seáis de Madrid y es un día laborable con lo que, salvo la casualidad, sé que será muy difícil. (Yo antes viajaba a Barcelona de vez en cuando, ahora no viajo nada, pero a lo mejor ariznaf, _GUI_ o algún otro van por allí de vez en cuando).
No sé si resultará una reunión productiva, pero al menos nos vemos y nos tomamos algo. Hay algunos detalles que no es bueno discutir tan públicamente (como el nombre del dominio y otras cosas que se me ocurren).
(por ariznaf) completamente de acuerdo. Además siempre hay curiosidad de ver la cara al interlocutor.
¿Opiniones? ¿Ideas? ¿Problemas?
Un saludo:
Última edición por ManuelLlorens; 20/05/2008 a las 14:28
Lo has detectado antes de que lo pudiera comentar.jeje, os habéis dado cuenta de que podemos editarnos los posts entre nosotros? o sea, aunque no sean nuestros.
Al objeto de poder organizar mejor los mensajes y facilitar la lectura de los mismos cuando buscamos sobre temas concretos, he pedido a Ojodigital dos cosas:
-Que nos permitan ser moderadores de este foro. Así cuando un bug se da por arreglado por ejemplo, podremos cerrar el hilo (lo consideraremos como una incidencia resuelta9. Si luego aparecen nuevos problemas, se ha de abrir otro hilo (incidencia).
Es por eso por lo que puedes modificar los posts, porque eres moderador. Pero ojito, que las modificaciones realizadas quedan marcadas y registradas, de forma que todo el mundo verá que has editado el post
-Que nos crearan algún subforo nuevo. No he pedido muchos, sólo los más básicos, para separar lo relacionado con la programación, el "reporte" de bugs y la solicitud de nuevas funcionalidades.
Así en vez de un hilo sobre bugs en el que meterlos todos (que luego se hace muy difícil de seguir en qué punto está la resolución de uno de los bugs o la implementación de una característica) se puede abrir un post para cada uno de ellos y ver en todo momento en qué estado está.
Con esto pretendo facilitar el desarrollo y el mantenimiento de la aplicación (sobre todo cara al futuro inmediato, cuando habrá un montón de frentes abiertos... bueno ya los hay).
Bueno, ahora a ver si somos nosotros mismos un poco organizaditos (yo me lanzo muchas veces a tratar temas sin pensar muy bien si el hilo es el adecuado).
Voy a mover lo hilos existentes que corresponden claramente a los nuevos subforos.
¿Os parece bien?
Saludines....
Última edición por ariznaf; 20/05/2008 a las 10:13
No estaría de más que alguien que no estuviera en lo de la programación pero que tuviera interés en este proyecto y algo de experiencia con lo de los foros se apuntara a moderar este foro.
Se encargaría de poner un poco de orden (tampoco se trata de tener un policía y normas superestrictas, sólo de contestar las preguntas evidentes de los nuevos que puedan llegar, mover algún hilo claramente fuera de sitio y ese tipo de cosas).
(por Manuel): su nombre aparecería en los créditos de la aplicación, es lo poco que podemos ofrecer. Por cierto, aprovecho para proponer que en los créditos de la aplicación aparezca todo el que haya tenido algo que ver con ella en orden alfabético, así no nos peleamos. O eso o definimos claramente cómo aparecerá cada uno.
Última edición por ManuelLlorens; 20/05/2008 a las 11:13
No me funciona en XP el programa puesto en Enlace al nuevo revelador
Cuando lo lanzo me da una excepción de AccessViolation. Primero aparece un cuadro de diálogo explicando que no se deben hacer dos revelados seguidos.
¿Tiene la misma interface que tenía con un botón para seleccionar imagen o es que estás intentando abrir una imagen raw directamente que yo no tengo en el equipo?
¡Ah! claro... eso es. Es que he cambiado el modo de inicializar la DLL para sortear el casque que aún tiene y al hacerlo me lo he cargadomás. Ya te dije anoche que me tenía que ir a la cama. A ver si recupero un poco de energía, programo más concentrado y cometo menos errores.
Bueno es fácil de arreglar, aunque un poco chapuza, hasta que lo suba de nuevo. Tenéis que aseguraros de que existe c:\test\1_a.dng y ya está. Podéis ir cambiando la imagen pero tendréis que cerrar y abrir la aplicación. Al mediodía lo subo arreglado para los más pacientes. De paso meteré excepciones para tratar los casos más evidentes y si me da tiempo meto la LUT sRGB rápida y la salida a 16 bits en el revelador.
Un saludo:
Última edición por ManuelLlorens; 20/05/2008 a las 11:10
Bien ya está hecho. Se mantendrán durante diez días enlaces en el foro raíz a los temas movidos.
Manuel: a veces he visto que hay lío y confusión cuando alguien comunica un problema con uno de los test, pues están comentando problemas sobre un test viejo, que ya fueron corregidos en test posteriores.
No es de extrañar que en un hilo tan largo como este pueda pasar desapercibido un mensaje en el que subas un nuevo programa de prueba (salvo para los más asiduos, claro)
Por ello te propongo el siguiente sencillo esquema de funcionamiento para cualquier programa de prueba que se quiera poner a disposición de los demás.
Crear un anuncio en el post principal que nitifique su creación identificando claramente la versión del programa de prueba. Este hilo se ha de crear como cerrado (para que no se respondan mensajes en él con problemas y demás y tener un único sitio de notificación de problemas).
Algo asÍ:
Crear también un nuevo hilo "Notificación de problemas de XXXXX versión YY".Nueva versión YY de prueba del programa XXXX
He subido a (enlace a donde sea) una nueva versión del programa XXX qu hace esto y aquello....
Para notificar errores en el funcionamiento del programa o comentarios sobre su forma de funcionar, házlo en el hilo (enlace al hilo del foro bugs)
A ver qué os parece esa forma de funcionar y si es ágil y funcional.
Y dicho con la boca pequeña y sin que nadie se enfade....
Creo que ha llegado el momento de cerrar este hilo ...
Vamos ya por 14 páginas y para alguien que llegue de nuevas o no lo haya leido en algún tiempo, se hace interminable.
Además mezclamos en él infinidad de temas y se hace imposible localizar una respuesta concreata (ya sé que existe el buscador, pero ...)
Además se hace casi imposible poner un enlace a una respuesta concreat en otro hilo.
Sé que al principio nos costará un poquito, pues estamos acostumbrados a venir aquí y contestar directamente a lo último que ponemos.
Pero en un par de días, en cuanto se empiezen a separar los distintos temas lo tendremos más organizado y será todo mucho más fácil de leer.
Bueno no me pongo más pesado con esto que parezco la mamá rezongona.![]()
Yo creo que debemos mover a otros foros los mensajes que traten de temas concretos, pero un foro general siempre debe haberlo. Habrá cosas inclasificables, otras como organizarnos para quedar un día y vernos las caras, etc. que no encajarán en otros foros. Digo yo.
Un saludo:
Vale, ya he arreglado el control de exposición. No había leído todo el texto de _GUI_ antes de ponerme a implementar, de ahí mi error anterior.
Podéis probarlo en este enlace, que machaca al anterior. He vuelto a actualizarlo a las 18:30 con la gamma sRGB rápida en vez de usar la de dcraw, es considerablemente más rápido. Y una vez más a las 20:00 con un botón para grabar el resultado en JPEG (8 bits, calidad 96, gamma sRGB, sin perfil de color incrustado).
El código:
El algoritmo de exposición de _GUI_ funciona, de eso no hay ninguna duda. Supongo que está asumido que el usar la preservación de luces altas afecta ligeramente al contraste de la imagen de modo que si f<1.0 se aumenta y si f>1.0 disminuye, ¿verdad _GUI_? De hecho, en algunas imágenes según dónde caiga la zona de transición entre cada tramo de la curva de corrección de exposición, puede quedar más natural o más raro, especialmente en retratos y transiciones suaves. Imagino que el control de exposición con preservación de luces altas, especialmente al disminuir la exposición, habrá que usarlo con cuidado y evaluar su efecto en cada imagen. He revelado un ejemplo (mola, porque es el primer ejemplo que ponemos que se ha revelado con perfectRAW, la interpolación del ejemplo es una caca):Código:void exposure_correction(void){ int i; float Y, Yp, exposure2, K1, K2; if(verbose) printf("Exposure correction "); if(exposure_mode==0){ // Exposure correction without highlight preservation if(verbose) printf("without highlight preservation\n"); for(i=0;i<height*width;i++){ image[i][0]=CLIPF((float)image[i][0]*exposure); // R image[i][1]=CLIPF((float)image[i][1]*exposure); // G (mixed) image[i][2]=CLIPF((float)image[i][2]*exposure); // B } }else{ // Exposure correction with highlight preservation if(verbose) printf("with highlight preservation\n"); if(exposure>1){ K1=32768/exposure; K2=65535-K1; 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<K1){ image[i][0]=CLIPF((float)image[i][0]*exposure); // R image[i][1]=CLIPF((float)image[i][1]*exposure); // G (mixed) image[i][2]=CLIPF((float)image[i][2]*exposure); // B }else{ Yp=32767*(Y-65535)/K2+65535; exposure2=Yp/Y; image[i][0]=CLIPF((float)image[i][0]*exposure2); // R image[i][1]=CLIPF((float)image[i][1]*exposure2); // G (mixed) image[i][2]=CLIPF((float)image[i][2]*exposure2); // B } } }else{ K1=32768*exposure; K2=65535-K1; 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<32768){ image[i][0]=CLIPF((float)image[i][0]*exposure); // R image[i][1]=CLIPF((float)image[i][1]*exposure); // G (mixed) image[i][2]=CLIPF((float)image[i][2]*exposure); // B }else{ Yp=K2*(Y-65535)/32767+65535; exposure2=Yp/Y; image[i][0]=CLIPF((float)image[i][0]*exposure2); // R image[i][1]=CLIPF((float)image[i][1]*exposure2); // G (mixed) image[i][2]=CLIPF((float)image[i][2]*exposure2); // B } } } } }
El primero con control de exposición -2.0 y CON preservación de luces altas.
El segundo con control de exposición -1.0 y CON preservación de luces altas.
El tercero con control de exposición -1.0 y SIN preservación de luces altas.
Un saludo:
Última edición por ManuelLlorens; 20/05/2008 a las 20:17
Bueno lo he probado en un ordenador con XP SP2 y me funcionó bien.
Eso sí como el ordenador es una patata (Pentium 4 2GHz y 2GB) de RAM me he eternizado un poquito mientras revelaba la imagen estandar.
Ha tardado 30 segundos pero lo ha revelado (con ajuste de exposición y preservación de altas luces).
Lo he probado nuevamente con Vista 64 y me vuelve loco, porque hay veces que funciona tres ocuatro veces y luego no vuelve a funcionar, no es un tema de la foto, ya que la misma foto va a veces si a veces no.
Las veces que funciona, funciona correctamente el control de expocicion y la preservacion de luces.
¿Alguien que pruebe con la recuperación de altas luces de PerfectRaw sobre la foto puesta en el tema Recuperación altas luces distintos reveladores RAW por GUI y ponga os resultados?
La foto es la que está en esta dirección: http://users.uoi.gr/gianstam/test/_3160973.ORF
No se podrá guardar pero se puede hacer un corta y pega de la pantalla para comparar con los otros resultados de ese hilo.
Yo no lo puedo hacer porque en este ordenador no tengo ningún programa para poder pegar la imagen y exportarla a jpeg (en casa en Vista 64 no me pita).
¿Con Vista 64? Juraría que no funcionaba... daba el error nada más hacer el GetInfo de la imagen.Lo he probado nuevamente con Vista 64 y me vuelve loco, porque hay veces que funciona tres ocuatro veces y luego no vuelve a funcionar, no es un tema de la foto, ya que la misma foto va a veces si a veces no.
Las veces que funciona, funciona correctamente el control de expocicion y la preservacion de luces.
Esta noche lo probaré.
El control de exposición de _GUI_ no recupera luces altas, sólo las preserva, no existe una recuperación de luces de prefectRAW. De preservarlas se sigue encargando el algoritmo de dcraw y ese no ha cambiado. La gracia es poder controlar la exposición de la imagen en 32 bits y sin estropear las luces altas bien porque se quemen cosas que antes no se quemaban, bien porque se conviertan en un empasto gris.
Aquí tienes la imagen de ejemplo con exposure: 0.5 (viene a ser -1.0), preservación de luces altas y recuperación máxima de luces (-h 9):
y de nuevo la misma imagen con con exposure: 2 (viene a ser +1.0), preservación de luces altas y recuperación máxima de luces (-h 9):
Un saludo:
Tendréis que esperar a que arregle el bug que tengo localizado en dcraw.dll a ver si influye. Es posible que sí. Haré otro intento de compilar dcraw con VC++ para ver si ariznaf puede depurarlo en su Vista 64 cuando casque.
He subido una nueva prueba de perfectRAW con un botón que graba un jpeg a calidad 96 en la misma carpeta y con el mismo nombre que el archivo revelado (+".jpg"). La idea es hacer más fácil subir pruebas al foro. La imagen NO incluye el perfil de color sRGB, pero sí está corregida con gamma sRGB, al abrirla en PS tendréis que asignarle el perfil sRGB.
Un saludo:
Última edición por ManuelLlorens; 20/05/2008 a las 20:10
Joer, ¡qué bien va la cosa!
A ver si luego puedo bajármelo y probarlo pero avanza a pasos de gigante! :-)
Daniel
¿Está ampliada o algo así esta imagen?El primero con control de exposición -2.0 y CON preservación de luces altas.
El segundo con control de exposición -1.0 y CON preservación de luces altas.
El tercero con control de exposición -1.0 y SIN preservación de luces altas.
![]()
Se aprecia un extraño efecto en el pelo y los ojos.
Parece como un aliasing. Lo digo por si es algún efecto del demosaicing (un fallo) aunque creo que la interpolación la hace dcraw ¿no?
Pues a mi no me funciona el programa en Vista 64que decepción.
A ver a ver... si consigues que compile y se pueda ejecutar, aunque se la pegue luego será un gran avance, pues podremos ver qué le ocurre a ver si nos hacemos una idea.Tendréis que esperar a que arregle el bug que tengo localizado en dcraw.dll a ver si influye. Es posible que sí. Haré otro intento de compilar dcraw con VC++ para ver si ariznaf puede depurarlo en su Vista 64 cuando casque.
La preservación de luces al reducir la exposición (f<1.0) es demasiado agresiva, ese codo tan abrupto (mirar la gráfica de la derecha arriba) da lugar a que se manifieste la transición del penúltimo al último diafragma, el brillito de la nariz de la niña ha quedado literalmente aislado del resto de la imagen. De todos modos la imagen de la niña (es tu hija?) no tiene zonas quemadas así que ahí no estaría justificado su uso.
No queda más remedio que acudir a una curva no lineal, te paso el pseudocódigo esta noche. El cambio sería pasar de las curvas de arriba (izq. lineal vs lineal, der. log vs lineal), a las de abajo, mucho más progresivas. Implica usar una potencia (f2 = 2^(-Exp*(Y-1)/0,5) donde Exp es la subexposición en EV, p.ej. Exp=-2EV e Y>0.5 el valor lineal normalizado 0..1 de la luminosidad), pero esto ya lo tienes muy optimizado no?
Creo que debería funcionar bien; en log-log también es muy progresiva:
El contraste solo se altera en el último diafragma, donde lo aumentamos para poder preservar las altas luces. En todos los restantes diafragmas de luminosidad la corrección de exposición es lineal y por tanto no hay alteración de contraste. El tono no se altera en ningún caso.
Podéis probar el ajuste de exposición al alza con una imagen normal? no la del barco, que tiene las altas luces recuperadas y de partida presenta tonos extraños.
Cualquier RAW a punto de quemar, se revela y se le sube la exp. +1, +2, +3, con y sin preservación de altas luces, a ver qué tal va la curva recta para aumentar la exposición, o si también hay que corregirla.
Última edición por Guillermo Luijk; 20/05/2008 a las 21:06
"En ocasiones veo halos."
http://www.guillermoluijk.com para suscribirte haz clic aquí
Último contenido: PARA QUÉ SIRVE EL RANGO DINÁMICO?
El demosaicing de dcraw está en el más rápido, es eso junto con la caca de interpolación que hace GDI+. Es una captura de pantalla pasada a PS y ampliada en PS con NN. Por eso he puesto el botón de grabar JPEG porque el método de capturar pantalla para pruebas al 100% o más es un asco.
Un saludo:
Te subo un ejemplo como pedías... aunque tú puedes ejecutar el programa en casa sin problema, ya arreglé todo lo que fallaba en la prueba de anoche.
Exp: 0
Exp: +1 sin y con preservación:
Exp: +2 sin y con preservación:
Exp: +3 sin y con preservación:
Exp: -1 sin y con preservación:
Un saludo:
Última edición por ManuelLlorens; 20/05/2008 a las 22:11
hostia pues el aumento con preservación va de coxones, verdad? cómo lo veis? se pierde contraste (como no puede ser de otro modo), pero el tono se mantiene y la textura también. en las hojas la saturación parcial del canal verde llega pronto y se nota.
la reducción ahora pongo el código nuevo menos agresivo, pero ésa solo será útil en fotos con zonas quemadas.
Bueno el código corregido para f<1 sería:
quizá una versión similar para cuando aumentamos la exposición mejore los resultados vistos. Una curva más suave no descontrastará tanto las altas luces a costa de descontrastar más aún las muy altas luces. Te paso el código cuando lo tenga.Código:void exposure_correction(void){ int i; float Y, Yp, exposure2, K1, K2, EV; if(verbose) printf("Exposure correction "); if(exposure_mode==0){ // Exposure correction without highlight preservation if(verbose) printf("without highlight preservation\n"); for(i=0;i<height*width;i++){ image[i][0]=CLIPF((float)image[i][0]*exposure); // R image[i][1]=CLIPF((float)image[i][1]*exposure); // G (mixed) image[i][2]=CLIPF((float)image[i][2]*exposure); // B } }else{ // Exposure correction with highlight preservation if(verbose) printf("with highlight preservation\n"); if(exposure>1){ K1=32768/exposure; K2=65535-K1; 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<K1){ image[i][0]=CLIPF((float)image[i][0]*exposure); // R image[i][1]=CLIPF((float)image[i][1]*exposure); // G (mixed) image[i][2]=CLIPF((float)image[i][2]*exposure); // B }else{ Yp=32767*(Y-65535)/K2+65535; exposure2=Yp/Y; image[i][0]=CLIPF((float)image[i][0]*exposure2); // R image[i][1]=CLIPF((float)image[i][1]*exposure2); // G (mixed) image[i][2]=CLIPF((float)image[i][2]*exposure2); // B } } }else{ EV=log(exposure)/log(2) // Convertimos exp. lineal a EV 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<32768){ image[i][0]=CLIPF((float)image[i][0]*exposure); // R image[i][1]=CLIPF((float)image[i][1]*exposure); // G (mixed) image[i][2]=CLIPF((float)image[i][2]*exposure); // B }else{ exposure2=pow(2,-EV*(Y/65535-1)/0,5); image[i][0]=CLIPF((float)image[i][0]*exposure2); // R image[i][1]=CLIPF((float)image[i][1]*exposure2); // G (mixed) image[i][2]=CLIPF((float)image[i][2]*exposure2); // B } } } } }
Por cierto si f=1 esta función realizar el procesado como cuando f<1, te has asegurado de que nunca sea llamada si f=1?
Última edición por Guillermo Luijk; 20/05/2008 a las 23:13
"En ocasiones veo halos."
http://www.guillermoluijk.com para suscribirte haz clic aquí
Último contenido: PARA QUÉ SIRVE EL RANGO DINÁMICO?
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í.
Para f<1 sí por favor prueba lo que he propuesto, creo que mejorará. Si es así el esquema final de curvas quedaría:
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.
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.
Última edición por Guillermo Luijk; 21/05/2008 a las 01:27
"En ocasiones veo halos."
http://www.guillermoluijk.com para suscribirte haz clic aquí
Último contenido: PARA QUÉ SIRVE EL RANGO DINÁMICO?
Pues los resultados son espectaculares, la verda... Se puede subir la luminosidad general pero sin que se queme la imagen.
El reducirla, por lo que veo lo que hace es mantener las zonas brillantes mientras oscurece el resto pero de manera progresiva.... (esto lo veo menos interesante, aunque el efecto está muy consiguido).
Si señor ha quedado bien.
Dos cositas:
¿Se podría hacer el efecto contrario? Es decir mantener las zonas oscuras.
Quiero decir, que si la imagen tiene zonas brillantes que queremos reducir puede ser interesante que las zonas no pasen a negro.
De hecho es algo parecido a lo que hace el LightRoom con las curvas cuando modificamos las sombras o las luces altas. El lo separa en sombras, zonas oscuras, medias, altas y muy altas o algo así. Cada una se puede corregir por separado afectando algo a las vecinas.
Sólo que GUI lo hace con curvas lineales ¿no?
Creo que también sería interesante poder controlar el punto de transición, donde la curva prograsiva pasa a tener un valor constante de sub o sobre exposición
Creo que lo ideal sería poder tener una curva con dos puntos configurables. A la derecha e izda de esos puntos la exposición sería progresiva y en medio constante.
Así se podría controlar que zona de luminosidad de la imagen queremos afectar mayormente por la exposición, siendo fuera de esa franja progresiva.
Y ya puestos en una versión futura, poner un editor de la curva de transición en lineal.![]()
Última edición por ariznaf; 21/05/2008 a las 01:32
Es que aún no lo habéis probado con una imagen con amplias zonas quemadas, que es donde cobra sentido; para que las luces no se vayan a gris. Estos seguro de que con la última mejora y un RAW quemado se notará la utilidad.
Esto puede ser interesante, porque no todas las imágenes tienen igual porción de información en el último diafragma (que es el que he tomado yo como punto de cambio de comportamiento). Además es muy sencillo, basta un parámetro que afecte a las fórmulas. Lo peor es que el GUI se nos va llenando de cositas.
Respecto a la preservacción de sombras, poderse se puede hacer (como estamos en lineal preservar el tono es trivial, es lo fantástico de la edición lineal), pero se nos trastocaría el contraste de toda la imagen no solo de las altas luces.
Esto creo que ya entraría más en la filosofía de edición que de revelado y ajuste. Si esto sale bien no estaría nada mal atrevernos con un editor de curvas lineal; se podrían hacer virguerías.
"En ocasiones veo halos."
http://www.guillermoluijk.com para suscribirte haz clic aquí
Último contenido: PARA QUÉ SIRVE EL RANGO DINÁMICO?
Marcadores