Estoy construyendo una galería de fotos en Python y quiero ser capaz de generar rápidamente las miniaturas de las imágenes de alta resolución.

¿Cuál es la manera más rápida de alta calidad para generar las miniaturas de una variedad de fuentes de imagen?

Debería ser el uso de una biblioteca externa como imagemagick, o es que hay un interno eficiente manera de hacer esto?

Las dimensiones de la redimensionar imágenes (tamaño máximo):

120x120
720x720
1600x1600

Calidad es un problema, ya que quiero conservar como muchos de los colores originales como sea posible y minimizar los artefactos de compresión.

Gracias.

  • Usted puede usar Python Varita, que llama a Imagemagick para hacer eso. No puedo decir si es el más rápido. Python OpenCV puede ser más rápido.
InformationsquelleAutor ensnare | 2011-12-25

7 Comentarios

  1. 23

    Desea PIL esto se hace con facilidad

    from PIL import Image
    sizes = [(120,120), (720,720), (1600,1600)]
    files = ['a.jpg','b.jpg','c.jpg']
    
    for image in files:
        for size in sizes:
            im = Image.open(image)
            im.thumbnail(size)
            im.save("thumbnail_%s_%s" % (image, "_".join(size)))

    Si usted necesita desesperadamente de velocidad. A continuación, hilo, multiproceso o conseguir otro idioma.

    • La última versión de PIL ya no admite import Image debería utilizar en su lugar from PIL import Image
    • Además, este código sólo guarda 3 miniaturas aunque va a generar todos los 9 miniaturas (usted probablemente tendrá que usar thumbnail_%s_%s-%s" % (image, size[0], size[1])).
    • Parece extraño a cargar la misma imagen de alta resolución de 3 veces de disco para generar de 3 miniaturas. Por qué no se carga la imagen de alta resolución de una vez, reducir la escala de 1600, escribir, bajar a 720, escribir, bajar a 120 y escribir? Seguramente tiene que ser más rápido.
  2. 15

    Me pareció un poco de diversión así que hice un poco de benchmarking de los diversos métodos sugeridos por encima y un par de mis propias ideas.

    He recopilado 1000 de alta resolución de 12 mp iPhone 6S imágenes, cada 4032×3024 pixels y el uso de 8-core iMac.

    Aquí son las técnicas y los resultados de cada uno en su propia sección.


    Método 1 – Secuencial ImageMagick

    Este es simplista, unoptimised código. Cada imagen es de lectura y una imagen en miniatura que se produce. A continuación, se lee de nuevo y de diferentes tamaños miniatura que se produce.

    #!/bin/bash
    
    start=$SECONDS
    # Loop over all files
    for f in image*.jpg; do
       # Loop over all sizes
       for s in 1600 720 120; do
          echo Reducing $f to ${s}x${s}
          convert "$f" -resize ${s}x${s} t-$f-$s.jpg
       done
    done
    echo Time: $((SECONDS-start))

    Resultado: 170 segundos


    Método 2 – Secuencial ImageMagick con una sola carga y sucesivas cambio de tamaño de

    Esto todavía es secuencial pero un poco más inteligente. Cada imagen es solo leer una vez y la imagen cargada y cambia entonces tres veces y se guardan en tres resoluciones. La mejora es que cada imagen es leer sólo una vez, no 3 veces.

    #!/bin/bash
    
    start=$SECONDS
    # Loop over all files
    N=1
    for f in image*.jpg; do
       echo Resizing $f
       # Load once and successively scale down
       convert "$f"                              \
          -resize 1600x1600 -write t-$N-1600.jpg \
          -resize 720x720   -write t-$N-720.jpg  \
          -resize 120x120          t-$N-120.jpg
       ((N=N+1))
    done
    echo Time: $((SECONDS-start))

    Resultado: 76 segundos


    Método 3 – GNU Paralelo + ImageMagick

    Esto se basa en el método anterior, mediante el uso de GNU Paralelo a proceso N imágenes en paralelo, donde N es el número de núcleos de CPU de la máquina.

    #!/bin/bash
    
    start=$SECONDS
    
    doit() {
       file=$1
       index=$2
       convert "$file"                               \
          -resize 1600x1600 -write t-$index-1600.jpg \
          -resize 720x720   -write t-$index-720.jpg  \
          -resize 120x120          t-$index-120.jpg
    }
    
    # Export doit() to subshells for GNU Parallel   
    export -f doit
    
    # Use GNU Parallel to do them all in parallel
    parallel doit {} {#} ::: *.jpg
    
    echo Time: $((SECONDS-start))

    Resultado: 18 segundos


    Método 4 – GNU Paralelo + vips

    Este es el mismo que el método anterior, pero utiliza vips en la línea de comandos en lugar de ImageMagick.

    #!/bin/bash
    
    start=$SECONDS
    
    doit() {
       file=$1
       index=$2
       r0=t-$index-1600.jpg
       r1=t-$index-720.jpg
       r2=t-$index-120.jpg
       vipsthumbnail "$file"  -s 1600 -o "$r0"
       vipsthumbnail "$r0"    -s 720  -o "$r1"
       vipsthumbnail "$r1"    -s 120  -o "$r2"
    }
    
    # Export doit() to subshells for GNU Parallel   
    export -f doit
    
    # Use GNU Parallel to do them all in parallel
    parallel doit {} {#} ::: *.jpg
    
    echo Time: $((SECONDS-start))

    Resultado: 8 segundos


    Método 5 – Secuencial PIL

    Esta es la intención de corresponder a Jakob respuesta.

    #!/usr/local/bin/python3
    
    import glob
    from PIL import Image
    
    sizes = [(120,120), (720,720), (1600,1600)]
    files = glob.glob('image*.jpg')
    
    N=0
    for image in files:
        for size in sizes:
          im=Image.open(image)
          im.thumbnail(size)
          im.save("t-%d-%s.jpg" % (N,size[0]))
        N=N+1

    Resultado: 38 segundos


    Método 6 – Secuencial PIL con una sola carga & sucesivas cambiar el tamaño de

    Este es concebido como una mejora a Jakob la respuesta, en la cual la imagen se carga una sola vez y, a continuación, cambiar de tamaño hacia abajo tres veces en lugar de volver a cargar cada vez que para producir cada nueva resolución.

    #!/usr/local/bin/python3
    
    import glob
    from PIL import Image
    
    sizes = [(120,120), (720,720), (1600,1600)]
    files = glob.glob('image*.jpg')
    
    N=0
    for image in files:
       # Load just once, then successively scale down
       im=Image.open(image)
       im.thumbnail((1600,1600))
       im.save("t-%d-1600.jpg" % (N))
       im.thumbnail((720,720))
       im.save("t-%d-720.jpg"  % (N))
       im.thumbnail((120,120))
       im.save("t-%d-120.jpg"  % (N))
       N=N+1

    Resultado: 27 segundos


    Método 7 – Paralelo PIL

    Esta es la intención de corresponder a Audionautics respuesta, en la medida en que utiliza Python del multiprocesamiento. También evita la necesidad de volver a cargar la imagen para cada tamaño de miniatura.

    #!/usr/local/bin/python3
    
    import glob
    from PIL import Image
    from multiprocessing import Pool 
    
    def thumbnail(params): 
        filename, N = params
        try:
            # Load just once, then successively scale down
            im=Image.open(filename)
            im.thumbnail((1600,1600))
            im.save("t-%d-1600.jpg" % (N))
            im.thumbnail((720,720))
            im.save("t-%d-720.jpg"  % (N))
            im.thumbnail((120,120))
            im.save("t-%d-120.jpg"  % (N))
            return 'OK'
        except Exception as e: 
            return e 
    
    
    files = glob.glob('image*.jpg')
    pool = Pool(8)
    results = pool.map(thumbnail, zip(files,range((len(files)))))

    Resultado: 6 segundos


    Método 8 – Paralelo OpenCV

    Este está destinado a ser una mejora en la bestia de la respuesta, en la medida en que los usos de OpenCV pero también evita la necesidad de volver a cargar la imagen para generar cada nueva resolución de salida.

    #!/usr/local/bin/python3
    
    import cv2
    import glob
    from multiprocessing import Pool 
    
    def thumbnail(params): 
        filename, N = params
        try:
            # Load just once, then successively scale down
            im = cv2.imread(filename)
            im = cv2.resize(im, (1600,1600))
            cv2.imwrite("t-%d-1600.jpg" % N, im) 
            im = cv2.resize(im, (720,720))
            cv2.imwrite("t-%d-720.jpg" % N, im) 
            im = cv2.resize(im, (120,120))
            cv2.imwrite("t-%d-120.jpg" % N, im) 
            return 'OK'
        except Exception as e: 
            return e 
    
    
    files = glob.glob('image*.jpg')
    pool = Pool(8)
    results = pool.map(thumbnail, zip(files,range((len(files)))))

    Resultado: 5 segundos

    • Bonita comparación, Marca
    • Esta respuesta es muy superior a la de todos los de arriba (y aceptado) respuestas
    • ¿El uso de vainilla PIL o una Almohada-simd?
    • Vainilla PIL.
    • Gracias, sí, este se alinea con lo que me he encontrado. El uso de una Almohada simd+multiprocesamiento+libjpegturbo estoy un promedio de alrededor de 1.2 segundos para un (3840,2160)->(512,512) cambiar el tamaño. Todavía un poco doloroso para varios miles de imágenes :/
  3. 12

    Un poco tarde a la pregunta (sólo un año!), pero voy a piggy respaldo en el «multiproceso» parte de @JakobBowyer la respuesta.

    Este es un buen ejemplo de un paralela problema, como el principal bits de código no mutar cualquier estado externo a sí mismo. Simplemente, se lee en una entrada, realiza su cálculo y guarda el resultado.

    Python es bastante buena en este tipo de problemas gracias a la función map proporcionada por multiprocessing.Pool.

    from PIL import Image
    from multiprocessing import Pool 
    
    def thumbnail(image_details): 
        size, filename = image_details
        try:
            im = Image.open(filename)
            im.thumbnail(size)
            im.save("thumbnail_%s" % filename)
            return 'OK'
        except Exception as e: 
            return e 
    
    sizes = [(120,120), (720,720), (1600,1600)]
    files = ['a.jpg','b.jpg','c.jpg']
    
    pool = Pool(number_of_cores_to_use)
    results = pool.map(thumbnail, zip(sizes, files))

    El núcleo de el código es exactamente el mismo que @JakobBowyer, pero en lugar de correr en un bucle en un solo hilo, que nos envolvió en una función extendió a través de múltiples núcleos a través de la multiprocesamiento función de mapa.

    • No quieres un producto Cartesiano en lugar de zip aunque?
    • El zip se refiere a la esta función, no el formato de archivo comprimido.
    • no esta por encima de secuencia de comandos de añadir ningún beneficio si número de núcleos se establece en uno?
    • búsqueda de producto Cartesiano. Esto va a generar la miniatura de la primera imagen en 120×120, para el segundo en 720×720, y para la última imagen en 1600×1600
  4. 4

    Otra opción es utilizar el enlaces python a OpenCV. Esto puede ser más rápido que el PIL o Imagemagick.

    import cv2
    
    sizes = [(120, 120), (720, 720), (1600, 1600)]
    image = cv2.imread("input.jpg")
    for size in sizes:
        resized_image = cv2.resize(image, size)
        cv2.imwrite("thumbnail_%d.jpg" % size[0], resized_image) 

    Hay un más completo tutorial aquí.

    Si usted desea que se ejecute en paralelo, el uso de concurrente.de futuros en Py3 o la de futuros paquete en Py2.7:

    import concurrent.futures
    import cv2
    
    def resize(input_filename, size):
        image = cv2.imread(input_filename)
        resized_image = cv2.resize(image, size)
        cv2.imwrite("thumbnail_%s%d.jpg" % (input_filename.split('.')[0], size[0]), resized_image)
    
    executor = concurrent.futures.ThreadPoolExecutor(max_workers=3)
    sizes = [(120, 120), (720, 720), (1600, 1600)]
    for size in sizes:
        executor.submit(resize, "input.jpg", size)
  5. 3

    Si usted ya está familiarizado con imagemagick, ¿por qué no seguir con el python-enlaces?

    PythonMagick

    • Gracias — esto es más rápido que algunos de los builtin Python métodos?
    • Que builtin métodos? Si te refieres a PIL, yo no puedo decir seguro, pero ImageMagick es más que el suizo-ejército-cuchillo, a continuación, un caballo de carreras. Sin embargo, yo nunca podría quejan de la actuación, pero sólo disfrutar las increíbles características. Yo no sé acerca de cualquier otra biblioteca con funciones similares.
  6. 2

    Python 2.7, Windows x64 usuarios

    Además @JakobBowyer & @Audionautics, PIL es bastante viejo y usted puede encontrar a sí mismo la solución de problemas y buscando la mejor versión… en su lugar, utilice Pillow de aquí (fuente)

    la actualización del fragmento de código se verá así:

    im = Image.open(full_path)
    im.thumbnail(thumbnail_size)
    im.save(new_path, "JPEG")

    enumeración completa de secuencia de comandos para la creación de la miniatura:

    import os
    from PIL import Image
    
    output_dir = '.\output'
    thumbnail_size = (200,200)
    
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    
    for dirpath, dnames, fnames in os.walk(".\input"):
        for f in fnames:
            full_path = os.path.join(dirpath, f)
            if f.endswith(".jpg"):
                filename = 'thubmnail_{0}'.format(f) 
                new_path = os.path.join(output_dir, filename)
    
                if os.path.exists(new_path):
                    os.remove(new_path)
    
                im = Image.open(full_path)
                im.thumbnail(thumbnail_size)
                im.save(new_path, "JPEG")
    • En windows tienes que construir desde el código fuente para obtener JPEG apoyo…

Dejar respuesta

Please enter your comment!
Please enter your name here