domingo, 10 de julio de 2016

Análisis de viñeteo en ópticas con R

Cuando se hacen fotografías con objetivos muy luminosos (se denomina así a aquellos que permiten que entre gran cantidad de luz en la cámara), se produce un fenómeno denominado viñeteo, por el cual en las esquinas y bordes de la imagen se captura una cantidad de luz inferior a la registrada en el centro. Esto da lugar a un oscurecimiento visible de la periferia.



Con el fin de calcular con precisión y rapidez la forma en que se pierde luminosidad a medida que nos alejamos del centro, he usado R para leer valores de luminosidad sobre la diagonal de la anterior imagen obteniendo de este modo el perfil de viñeteo.

Para la prueba se han adaptado los objetivos Canon New FD 35mm f/2, 50mm f/1,4 y 85mm f/1,8 a una Sony A7 II. Las tomas se hicieron a máxima apertura (cuando más afecta el viñeteo), sobre una superficie de luminosidad uniforme, y con enfoque a infinito para no capturar textura del sujeto.



Los archivos RAW generados se revelan de manera neutra y lineal con DCRAW, sin aplicar balance de blancos ni conversión a un perfil de color de salida:

    dcraw -v -r 1 1 1 1 -o 0 -4 -T *.DNG

Obtenidas las imágenes en TIFF, las convertimos a formato PNG y las cargamos como arrays en R usando el paquete "png", tras lo cual resultará muy sencillo acceder a los datos de imagen para procesarlos:

    # Leemos imágenes
    library(png)
    f35=readPNG("35mm.png")
    f50=readPNG("50mm.png")
    f85=readPNG("85mm.png")

En un paso intermedio sumarizamos los tres canales RGB de cada imagen en una luminosidad. Puede verse cómo la vectorización de operaciones en R ahorra los bucles anidados inevitables en cualquier lenguaje de programación tradicional, permitiendo leer y procesar una imagen completa con una sola línea de código:

    # Combinamos los 3 canales en los 3 objetivos
    NUMOBJ=3
    lum=array(0,dim=c(dim(f35[,,1]), NUMOBJ))

    lum[,,1]=
    0.299*f35[,,1]+0.587*f35[,,2]+0.114*f35[,,3]
    lum[,,2]=
    0.299*f50[,,1]+0.587*f50[,,2]+0.114*f50[,,3]
    lum[,,3]=
    0.299*f85[,,1]+0.587*f85[,,2]+0.114*f85[,,3]

Con la luminosidad calculamos el perfil del viñeteo para cada uno de los objetivos:

    # Calculamos el perfil de esquina a esquina
    # pasando por el centro de la imagen
    perfil=array(0,dim=c(ncol(lum), NUMOBJ))


    for (objetivo in 1:NUMOBJ) {
       for (x in 1:1024) {
         y=(681-1)/(1024-1)*(x-1)+1
         # Con (x,y) recorremos la diagonal
         perfil[x, objetivo] = lum[y, x, objetivo]
       }
    }

Conseguidos los perfiles dibujamos sus gráficas con escala logarítmica en base 2 (la habitual en el mundo fotográfico), obteniendo el siguiente resultado al superponer las curvas de cada óptica:



El eje x representa la posición sobre la diagonal del círculo de imagen en el rango normalizado -0,5 a +0,5, marcando en línea discontínua los límites correspondientes a las esquinas. Las otras dos parejas de líneas discontínuas representan las posiciones de los extremos izquierdo/derecho, y superior/inferior de la imagen.

Como era de esperar, la óptica más luminosa (50mm f/1,4) es la que más viñeteo produce a máxima apertura, siguiéndole el objetivo más angular (35mm f/2) pese a ser algo menos luminoso que el tele (85mm f/1,8).

La ligera asimetría de los perfiles se debe a que los patrones circulares no estaban del todo centrados por existir cierto gradiente de luminosidad en la superficie medida. Dicho gradiente es muy difícil de erradicar en su totalidad, especialmente con las focales más angulares.


~~~

Repositorio con el código R y archivos auxiliares: GitHub.

No hay comentarios:

Publicar un comentario

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.