Come posso ridimensionare un'immagine usando PIL e mantenerne le proporzioni?


437

C'è un modo ovvio per farlo che mi manca? Sto solo cercando di creare miniature.


9
Poiché questa domanda è piuttosto vecchia ma utile e il cuscino è piuttosto preferito, per un tutorial basato sui cuscini dai un'occhiata a questo: pillow.readthedocs.org/en/latest/handbook/…
Wtower

3
Ho creato una piccola libreria per ridimensionare le immagini, può essere di qualsiasi aiuto: github.com/charlesthk/python-resize-image
Charlesthk,

L'ultima versione di PIL è stata nel 2006. Il pacchetto di cuscini è il rimpiazzo per quanto ne so. L'ultima uscita di Pillow è stata il 2 aprile 2020.
David Medinets il

Risposte:


477

Definire una dimensione massima. Quindi, calcola un rapporto di ridimensionamento prendendo min(maxwidth/width, maxheight/height).

La dimensione corretta è oldsize*ratio.

Esiste ovviamente anche un metodo di libreria per fare questo: il metodo Image.thumbnail.
Di seguito è riportato un esempio (modificato) dalla documentazione PIL .

import os, sys
import Image

size = 128, 128

for infile in sys.argv[1:]:
    outfile = os.path.splitext(infile)[0] + ".thumbnail"
    if infile != outfile:
        try:
            im = Image.open(infile)
            im.thumbnail(size, Image.ANTIALIAS)
            im.save(outfile, "JPEG")
        except IOError:
            print "cannot create thumbnail for '%s'" % infile

4
Come dice, l'esempio era dalla documentazione pil e quell'esempio (ancora) non usa il flag antialias. Dal momento che è probabilmente quello che la maggior parte della gente vorrebbe, però, l'ho aggiunto.
Gnud,

3
PIL imposta l'altezza della nuova immagine sulla dimensione indicata (128 qui) e calcola la larghezza per mantenere le proporzioni. C'è un modo per correggere la larghezza anziché l'altezza? forse lo farò in una domanda separata.
Eugene,

6
@Eugene: provare qualcosa del genere s= img.size(); ratio = MAXWIDTH/s[0]; newimg = img.resize((s[0]*ratio, s[1]*ratio), Image.ANTIALIAS)? (Questo è per la divisione in virgola mobile però :)
gnud

48
Si noti che ANTIALIASnon è più preferito per gli utenti della famosa forcella Pillow di PIL. pillow.readthedocs.org/en/3.0.x/releasenotes/…
Joshmaker il

8
La documentazione di Python 3 per PIL afferma che thumbnailfunziona solo se l'immagine risultante è più piccola di quella originale. Per questo immagino che usare resizesia il modo migliore.
Quindi,

254

Questo script ridimensionerà un'immagine (somepic.jpg) usando PIL (Python Imaging Library) su una larghezza di 300 pixel e un'altezza proporzionale alla nuova larghezza. Lo fa determinando quale percentuale di 300 pixel è della larghezza originale (img.size [0]) e quindi moltiplicando l'altezza originale (img.size [1]) per quella percentuale. Cambia "basewidth" con qualsiasi altro numero per cambiare la larghezza predefinita delle tue immagini.

from PIL import Image

basewidth = 300
img = Image.open('somepic.jpg')
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((basewidth,hsize), Image.ANTIALIAS)
img.save('sompic.jpg') 

2
Se stai usando questo script in Zope come metodo esterno avrai bisogno della riga "dall'immagine di importazione PIL" per evitare scontri nello spazio dei nomi con "Immagine" di Zope.
Tomvon,

Questo codice mi dà un file di output di 0 byte sompic.jpg. Perché succede? Sto usando Python 3.x
imrek il

- Aggiornamento: lo stesso accade in Python 2.7.
imrek,

Potrei aver capito. Se stai salvando un .jpeg, usa img.save('sompic.jpg', 'JPEG').
imrek,

5
nit: non esiste alcuna PIL.Image.ANTIALIASopzione per resize, in realtà dovrebbe esserlo PIL.Image.LANCZOS, sebbene siano entrambi 1di valore, vedi pillow.readthedocs.io/en/3.1.x/reference/…
Fred Wu

66

Consiglio anche di utilizzare il metodo delle miniature PIL, perché rimuove tutti i fastidi del rapporto da te.

Un suggerimento importante, però: sostituire

im.thumbnail(size)

con

im.thumbnail(size,Image.ANTIALIAS)

per impostazione predefinita, PIL utilizza il filtro Image.NEAREST per il ridimensionamento, il che si traduce in buone prestazioni, ma scarsa qualità.


2
Con questo, puoi solo ridurre la dimensione di un'immagine. Non è possibile aumentare le dimensioni con Image.thumbnail.
bruciato

45

Basato su @tomvon, ho finito di usare il seguente (scegli il tuo caso):

a) Altezza di ridimensionamento ( conosco la nuova larghezza, quindi ho bisogno della nuova altezza )

new_width  = 680
new_height = new_width * height / width 

b) Ridimensionare la larghezza ( conosco la nuova altezza, quindi ho bisogno della nuova larghezza )

new_height = 680
new_width  = new_height * width / height

Quindi solo:

img = img.resize((new_width, new_height), Image.ANTIALIAS)

6
Le tue variabili sono tutte confuse. Il tuo post dice ridimensionare la larghezza, quindi ridimensiona l'altezza. E nella resizechiamata, stai usando new_widthsia per altezza che per larghezza?
Zachafer,

Suggerito una correzione per quel @Zachafer
Mo Beigi

1
Meglio convertirli in numeri interi
Black Thunder,

18

PIL ha già la possibilità di ritagliare un'immagine

img = ImageOps.fit(img, size, Image.ANTIALIAS)

20
Ciò ritaglia semplicemente l'immagine, non mantiene le proporzioni.
Radu,

2
Questo non risponde in alcun modo alla domanda.
AMC,

15
from PIL import Image

img = Image.open('/your image path/image.jpg') # image extension *.png,*.jpg
new_width  = 200
new_height = 300
img = img.resize((new_width, new_height), Image.ANTIALIAS)
img.save('output image name.png') # format may what you want *.png, *jpg, *.gif

8
Ciò non mantiene le proporzioni dell'immagine sorgente. Forza l'immagine a 200x300 e si tradurrà in un'immagine compressa o allungata.
bruciato

Questo non risponde in alcun modo alla domanda.
AMC,

13

Se stai cercando di mantenere le stesse proporzioni, non ridimensioneresti di una percentuale delle dimensioni originali?

Ad esempio, metà delle dimensioni originali

half = 0.5
out = im.resize( [int(half * s) for s in im.size] )

13
È possibile che le immagini fossero di dimensioni variabili e che il risultato del ridimensionamento fosse di dimensioni uniformi
Steen

7
from PIL import Image
from resizeimage import resizeimage

def resize_file(in_file, out_file, size):
    with open(in_file) as fd:
        image = resizeimage.resize_thumbnail(Image.open(fd), size)
    image.save(out_file)
    image.close()

resize_file('foo.tif', 'foo_small.jpg', (256, 256))

Uso questa libreria:

pip install python-resize-image

7

Se non vuoi / non hai bisogno di aprire l'immagine con Pillow, usa questo:

from PIL import Image

new_img_arr = numpy.array(Image.fromarray(img_arr).resize((new_width, new_height), Image.ANTIALIAS))

4

Basta aggiornare questa domanda con un wrapper più moderno Questa libreria avvolge Pillow (una forcella di PIL) https://pypi.org/project/python-resize-image/

Ti permette di fare qualcosa del genere: -

from PIL import Image
from resizeimage import resizeimage

fd_img = open('test-image.jpeg', 'r')
img = Image.open(fd_img)
img = resizeimage.resize_width(img, 200)
img.save('test-image-width.jpeg', img.format)
fd_img.close()

Moltissimi altri esempi nel link sopra.


3
resize_contain sembra in realtà abbastanza utile!
Anytoe,

4

Stavo cercando di ridimensionare alcune immagini per un video di presentazione e per questo motivo non volevo solo una dimensione massima, ma una larghezza massima e un'altezza massima (le dimensioni del fotogramma video).
E c'era sempre la possibilità di un video ritratto ...
IlImage.thumbnail metodo era promettente, ma non sono riuscito a renderlo di lusso un'immagine più piccola.

Quindi dopo che non sono riuscito a trovare un modo ovvio per farlo qui (o in altri luoghi), ho scritto questa funzione e l'ho messa qui per quelli che verranno:

from PIL import Image

def get_resized_img(img_path, video_size):
    img = Image.open(img_path)
    width, height = video_size  # these are the MAX dimensions
    video_ratio = width / height
    img_ratio = img.size[0] / img.size[1]
    if video_ratio >= 1:  # the video is wide
        if img_ratio <= video_ratio:  # image is not wide enough
            width_new = int(height * img_ratio)
            size_new = width_new, height
        else:  # image is wider than video
            height_new = int(width / img_ratio)
            size_new = width, height_new
    else:  # the video is tall
        if img_ratio >= video_ratio:  # image is not tall enough
            height_new = int(width / img_ratio)
            size_new = width, height_new
        else:  # image is taller than video
            width_new = int(height * img_ratio)
            size_new = width_new, height
    return img.resize(size_new, resample=Image.LANCZOS)

3

Un metodo semplice per mantenere rapporti vincolati e passare una larghezza / altezza massima. Non è il più bello, ma fa il lavoro ed è facile da capire:

def resize(img_path, max_px_size, output_folder):
    with Image.open(img_path) as img:
        width_0, height_0 = img.size
        out_f_name = os.path.split(img_path)[-1]
        out_f_path = os.path.join(output_folder, out_f_name)

        if max((width_0, height_0)) <= max_px_size:
            print('writing {} to disk (no change from original)'.format(out_f_path))
            img.save(out_f_path)
            return

        if width_0 > height_0:
            wpercent = max_px_size / float(width_0)
            hsize = int(float(height_0) * float(wpercent))
            img = img.resize((max_px_size, hsize), Image.ANTIALIAS)
            print('writing {} to disk'.format(out_f_path))
            img.save(out_f_path)
            return

        if width_0 < height_0:
            hpercent = max_px_size / float(height_0)
            wsize = int(float(width_0) * float(hpercent))
            img = img.resize((max_px_size, wsize), Image.ANTIALIAS)
            print('writing {} to disk'.format(out_f_path))
            img.save(out_f_path)
            return

Ecco uno script Python che utilizza questa funzione per eseguire il ridimensionamento dell'immagine in batch.


3

Ho aggiornato la risposta sopra con "tomvon"

from PIL import Image

img = Image.open(image_path)

width, height = img.size[:2]

if height > width:
    baseheight = 64
    hpercent = (baseheight/float(img.size[1]))
    wsize = int((float(img.size[0])*float(hpercent)))
    img = img.resize((wsize, baseheight), Image.ANTIALIAS)
    img.save('resized.jpg')
else:
    basewidth = 64
    wpercent = (basewidth/float(img.size[0]))
    hsize = int((float(img.size[1])*float(wpercent)))
    img = img.resize((basewidth,hsize), Image.ANTIALIAS)
    img.save('resized.jpg')

Lavora come un fascino! Quindi grazie!
Denis Savenko,

2

Il mio brutto esempio.

La funzione ottiene il file come: "pic [0-9a-z]. [Extension]", ridimensionali a 120x120, sposta la sezione al centro e salva in "ico [0-9a-z]. [Extension]", funziona con il ritratto e paesaggio:

def imageResize(filepath):
    from PIL import Image
    file_dir=os.path.split(filepath)
    img = Image.open(filepath)

    if img.size[0] > img.size[1]:
        aspect = img.size[1]/120
        new_size = (img.size[0]/aspect, 120)
    else:
        aspect = img.size[0]/120
        new_size = (120, img.size[1]/aspect)
    img.resize(new_size).save(file_dir[0]+'/ico'+file_dir[1][3:])
    img = Image.open(file_dir[0]+'/ico'+file_dir[1][3:])

    if img.size[0] > img.size[1]:
        new_img = img.crop( (
            (((img.size[0])-120)/2),
            0,
            120+(((img.size[0])-120)/2),
            120
        ) )
    else:
        new_img = img.crop( (
            0,
            (((img.size[1])-120)/2),
            120,
            120+(((img.size[1])-120)/2)
        ) )

    new_img.save(file_dir[0]+'/ico'+file_dir[1][3:])

2

Ho ridimensionato l'immagine in questo modo e funziona molto bene

from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
import os, sys
from PIL import Image


def imageResize(image):
    outputIoStream = BytesIO()
    imageTemproaryResized = imageTemproary.resize( (1920,1080), Image.ANTIALIAS) 
    imageTemproaryResized.save(outputIoStream , format='PNG', quality='10') 
    outputIoStream.seek(0)
    uploadedImage = InMemoryUploadedFile(outputIoStream,'ImageField', "%s.jpg" % image.name.split('.')[0], 'image/jpeg', sys.getsizeof(outputIoStream), None)

    ## For upload local folder
    fs = FileSystemStorage()
    filename = fs.save(uploadedImage.name, uploadedImage)

2

Aggiungerò anche una versione del ridimensionamento che mantiene fisse le proporzioni. In questo caso, regolerà l'altezza in modo che corrisponda alla larghezza della nuova immagine, in base alle proporzioni iniziali, asp_rat , che è float (!). Tuttavia, per regolare la larghezza all'altezza, devi solo commentare una riga e rimuovere il commento dall'altra nel ciclo else . Vedrai dove.

Non hai bisogno dei punti e virgola (;), li tengo solo per ricordare a me stesso la sintassi delle lingue che uso più spesso.

from PIL import Image

img_path = "filename.png";
img = Image.open(img_path);     # puts our image to the buffer of the PIL.Image object

width, height = img.size;
asp_rat = width/height;

# Enter new width (in pixels)
new_width = 50;

# Enter new height (in pixels)
new_height = 54;

new_rat = new_width/new_height;

if (new_rat == asp_rat):
    img = img.resize((new_width, new_height), Image.ANTIALIAS); 

# adjusts the height to match the width
# NOTE: if you want to adjust the width to the height, instead -> 
# uncomment the second line (new_width) and comment the first one (new_height)
else:
    new_height = round(new_width / asp_rat);
    #new_width = round(new_height * asp_rat);
    img = img.resize((new_width, new_height), Image.ANTIALIAS);

# usage: resize((x,y), resample)
# resample filter -> PIL.Image.BILINEAR, PIL.Image.NEAREST (default), PIL.Image.BICUBIC, etc..
# https://pillow.readthedocs.io/en/3.1.x/reference/Image.html#PIL.Image.Image.resize

# Enter the name under which you would like to save the new image
img.save("outputname.png");

E fatto. Ho provato a documentarlo il più possibile, quindi è chiaro.

Spero possa essere utile a qualcuno là fuori!


0

Apri il tuo file immagine

from PIL import Image
im = Image.open("image.png")

Usa il metodo PIL Image.resize (size, resample = 0) , dove sostituisci (larghezza, altezza) della tua immagine con la dimensione di 2 tuple.

Questo visualizzerà la tua immagine nella dimensione originale:

display(im.resize((int(im.size[0]),int(im.size[1])), 0) )

Questo visualizzerà la tua immagine a 1/2 della dimensione:

display(im.resize((int(im.size[0]/2),int(im.size[1]/2)), 0) )

Questo visualizzerà la tua immagine a 1/3 della dimensione:

display(im.resize((int(im.size[0]/3),int(im.size[1]/3)), 0) )

Questo visualizzerà la tua immagine a 1/4 della dimensione:

display(im.resize((int(im.size[0]/4),int(im.size[1]/4)), 0) )

ecc ecc


Che cos'è display()e dove si trova?
Anthony,

0
from PIL import Image
from resizeimage import resizeimage

def resize_file(in_file, out_file, size):
    with open(in_file) as fd:
        image = resizeimage.resize_thumbnail(Image.open(fd), size)
    image.save(out_file)
    image.close()

resize_file('foo.tif', 'foo_small.jpg', (256, 256))

-1

Puoi ridimensionare l'immagine con il codice seguente:

From PIL import Image
img=Image.open('Filename.jpg') # paste image in python folder
print(img.size())
new_img=img.resize((400,400))
new_img.save('new_filename.jpg')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.