8

Tengo un script que utiliza Google Maps API para descargar una secuencia de imágenes satelitales cuadradas de igual tamaño y genera un PDF. Las imágenes deben girarse de antemano, y ya lo hago usando PIL.Normalizar el histograma (brillo y contraste) de un conjunto de imágenes usando Python Image Library (PIL)

Noté que, debido a las diferentes condiciones de luz y terreno, algunas imágenes son demasiado brillantes, otras son demasiado oscuras, y el pdf resultante termina un poco feo, con condiciones de lectura "in the field" (que es el ciclismo de montaña fuera de pista, donde quiero tener una miniatura impresa de encrucijadas específicas).

(EDITAR) El objetivo es hacer que todas las imágenes terminen con un brillo y contraste aparente similares. Por lo tanto, las imágenes que son demasiado brillantes tendrían que oscurecerse, y las oscuras tendrían que iluminarse. (Por cierto, una vez usé imagemagick autocontrast, o auto-gamma, o equalize, o autolevel, o algo así, con resultados interesantes en imágenes médicas, pero no sé cómo hacer ninguna de estas en PIL).

Ya utilicé algunas correcciones de imagen después de convertir a escala de grises (tenía una impresora en escala de grises hace un tiempo), pero los resultados tampoco fueron buenos. Aquí está mi código de escala de grises:

#!/usr/bin/python 

def myEqualize(im) 
    im=im.convert('L') 
    contr = ImageEnhance.Contrast(im) 
    im = contr.enhance(0.3) 
    bright = ImageEnhance.Brightness(im) 
    im = bright.enhance(2) 
    #im.show() 
    return im 

Este código funciona de forma independiente para cada imagen. Me pregunto si sería mejor analizar primero todas las imágenes y luego "normalizar" sus propiedades visuales (contraste, brillo, gamma, etc.).

Además, creo que sería necesario realizar algunos análisis en la imagen (¿histograma?), Para aplicar una corrección personalizada en función de cada imagen, y no una corrección igual para todos ellos (aunque cualquier "mejora" "la función considera implícitamente las conticiones iniciales).

¿Alguien tuvo tal problema y/o sabe una buena alternativa para hacer esto con las imágenes en color (sin escala de grises)?

Cualquier ayuda será apreciada, ¡gracias por leer!

+0

¡Buena pregunta! Sin embargo, se necesita alguna aclaración. Además, publicar imágenes de ejemplo sería muy útil para que las personas lo usen como casos de prueba. En primer lugar, ¿existe el problema de que los bordes de los mosaicos no coincidan bien cuando los descarga? ¿O estás buscando una forma de iluminar los mosaicos oscuros y atenuar los brillantes? ¿O necesitas hacer lo último mientras mantienes la continuidad de los bordes? – Paul

+0

Los bordes no son un problema, porque el conjunto de imágenes no es continuo. El objetivo es oscurecer a los más brillantes e iluminar a los oscuros, como dijiste. – heltonbiker

Respuesta

4

Lo que probablemente esté buscando es una utilidad que realice "estiramiento de histograma". Here is one implementation. Estoy seguro de que hay otros. Creo que desea conservar el tono original y aplicar esta función uniformemente en todas las bandas de color.

Por supuesto, hay una buena posibilidad de que algunas de las fichas tengan una discontinuidad notable en el nivel donde se unen. Evitar esto, sin embargo, implicaría la interpolación espacial de los parámetros de "estiramiento" y es una solución mucho más complicada. (... pero sería un buen ejercicio si existe esa necesidad.)

Editar:

Aquí es un pellizco que conserva la tonalidad de imagen:

import operator 

def equalize(im): 
    h = im.convert("L").histogram() 
    lut = [] 
    for b in range(0, len(h), 256): 
     # step size 
     step = reduce(operator.add, h[b:b+256])/255 
     # create equalization lookup table 
     n = 0 
     for i in range(256): 
      lut.append(n/step) 
      n = n + h[i+b] 
    # map image through lookup table 
    return im.point(lut*im.layers) 
+0

Guau, parece exactamente lo que quería. ¡Lo intentaré rápidamente y enviaré comentarios muy pronto! – heltonbiker

+0

En realidad, esta implementación parece funcionar una imagen a la vez, y estaba pensando en analizar todas las imágenes primero, y luego aplicar la ecualización. Además, las imágenes no se colocarán en mosaico, son de ubicaciones diferentes y generalmente no se superponen. Voy a probar tu sugerencia y ver lo que obtengo. ¡Gracias! – heltonbiker

+0

Lo probé en las imágenes digitales normales de mi cámara con excelentes resultados. Sin embargo, cuando lo probé en una pantalla de una imagen de satélite de Google, fue terrible. Creo que las imágenes sat están altamente posterizadas o algo así. – Paul

1

El siguiente código funciona en imágenes desde un microscopio (que son similares), para prepararlas antes de suturarlas. Lo usé en un conjunto de prueba de 20 imágenes, con resultados razonables.

La función promedio de brillo es de Stackoverflow question.

from PIL import Image 
from PIL import ImageStat 
import math 

# function to return average brightness of an image 
# Source: https://stackoverflow.com/questions/3490727/what-are-some-methods-to-analyze-image-brightness-using-python 

def brightness(im_file): 
    im = Image.open(im_file) 
    stat = ImageStat.Stat(im) 
    r,g,b = stat.mean 
    return math.sqrt(0.241*(r**2) + 0.691*(g**2) + 0.068*(b**2)) #this is a way of averaging the r g b values to derive "human-visible" brightness 

myList = [0.0] 
deltaList = [0.0] 
b = 0.0 
num_images = 20       # number of images 

# loop to auto-generate image names and run prior function 
for i in range(1, num_images + 1):  # for loop runs from image number 1 thru 20 
    a = str(i) 
    if len(a) == 1: a = '0' + str(i) # to follow the naming convention of files - 01.jpg, 02.jpg... 11.jpg etc. 
    image_name = 'twenty/' + a + '.jpg' 
    myList.append(brightness(image_name)) 

avg_brightness = sum(myList[1:])/num_images 
print myList 
print avg_brightness 

for i in range(1, num_images + 1): 
    deltaList.append(i) 
    deltaList[i] = avg_brightness - myList[i] 

print deltaList 

En este punto, los valores de "corrección" (es decir, la diferencia entre el valor y la media) se almacenan en deltaList.La siguiente sección aplica esta corrección a todas las imágenes una por una.

for k in range(1, num_images + 1):  # for loop runs from image number 1 thru 20 
    a = str(k) 
    if len(a) == 1: a = '0' + str(k)  # to follow the naming convention of files - 01.jpg, 02.jpg... 11.jpg etc. 
    image_name = 'twenty/' + a + '.jpg' 
    img_file = Image.open(image_name) 
    img_file = img_file.convert('RGB')  # converts image to RGB format 
    pixels = img_file.load()    # creates the pixel map 
    for i in range (img_file.size[0]): 
     for j in range (img_file.size[1]): 
     r, g, b = img_file.getpixel((i,j)) # extracts r g b values for the i x j th pixel 
     pixels[i,j] = (r+int(deltaList[k]), g+int(deltaList[k]), b+int(deltaList[k])) # re-creates the image 
    j = str(k) 
    new_image_name = 'twenty/' +'image' + j + '.jpg'  # creates a new filename 
    img_file.save(new_image_name)       # saves output to new file name 
Cuestiones relacionadas