Wie kann ich die Größe eines Bildes mithilfe von PIL ändern und das Seitenverhältnis beibehalten?


435

Gibt es einen offensichtlichen Weg, dies zu tun, den ich vermisse? Ich versuche nur, Thumbnails zu machen.


9
Da diese Frage ziemlich alt, aber nützlich ist und Kissen eher bevorzugt werden, sehen Sie sich für ein kissenbasiertes
Wtower

3
Ich habe eine kleine Bibliothek zum
Charlesthk

Die letzte Veröffentlichung von PIL war im Jahr 2006. Die Kissenpackung ist meines Wissens der Ersatz. Die neueste Version von Pillow war der 2. April 2020.
David Medinets

Antworten:


477

Definieren Sie eine maximale Größe. Berechnen Sie dann ein Größenänderungsverhältnis, indem Sie nehmen min(maxwidth/width, maxheight/height).

Die richtige Größe ist oldsize*ratio.

Dazu gibt es natürlich auch eine Bibliotheksmethode: die Methode Image.thumbnail.
Unten finden Sie ein (bearbeitetes) Beispiel aus der PIL-Dokumentation .

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
Wie es heißt, stammt das Beispiel aus der Pil-Dokumentation, und dieses Beispiel verwendet (noch) nicht das Antialias-Flag. Da es wahrscheinlich das ist, was die meisten Leute wollen würden, habe ich es hinzugefügt.
Gnud

3
PIL setzt die Höhe des neuen Bildes auf die angegebene Größe (hier 128) und berechnet die Breite, um das Seitenverhältnis beizubehalten. Gibt es eine Möglichkeit, die Breite anstelle der Höhe festzulegen? Vielleicht stelle ich das in einer separaten Frage.
Eugene

6
@ Eugene: versuchen Sie so etwas wie s= img.size(); ratio = MAXWIDTH/s[0]; newimg = img.resize((s[0]*ratio, s[1]*ratio), Image.ANTIALIAS)? (Das ist allerdings für die Gleitkommadivision :)
Gnud

48
Beachten Sie, dass dies ANTIALIASfür Benutzer der beliebten Pillow-Gabel von PIL nicht mehr bevorzugt wird. pillow.readthedocs.org/en/3.0.x/releasenotes/…
Joshmaker

8
Die Python 3- Dokumentation für PIL besagt, dass dies thumbnailnur funktioniert, wenn das resultierende Bild kleiner als das Original ist. Aus diesem Grund würde ich vermuten, dass die Verwendung resizeder bessere Weg ist.
Also S

253

Dieses Skript ändert die Größe eines Bildes (somepic.jpg) mithilfe von PIL (Python Imaging Library) auf eine Breite von 300 Pixel und eine Höhe proportional zur neuen Breite. Dazu wird ermittelt, wie viel Prozent 300 Pixel der ursprünglichen Breite (img.size [0]) entsprechen, und anschließend die ursprüngliche Höhe (img.size [1]) mit diesem Prozentsatz multipliziert. Ändern Sie "Basisbreite" in eine andere Zahl, um die Standardbreite Ihrer Bilder zu ändern.

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
Wenn Sie dieses Skript in Zope als externe Methode verwenden, benötigen Sie die Zeile "aus PIL-Importbild", um Namespace-Konflikte mit Zopes "Bild" zu vermeiden.
Tomvon

Dieser Code gibt mir eine 0-Byte-Ausgabedatei sompic.jpg. Warum passiert das? Ich benutze Python 3.x
imrek

- Update: Das gleiche passiert in Python 2.7.
Imrek

Ich habe es vielleicht herausgefunden. Wenn Sie a speichern .jpeg, verwenden Sie img.save('sompic.jpg', 'JPEG').
Imrek

5
nit: es gibt keine PIL.Image.ANTIALIASOption für resize, sollte eigentlich sein PIL.Image.LANCZOS, obwohl beide 1im Wert sind, siehe pillow.readthedocs.io/en/3.1.x/reference/…
Fred Wu

66

Ich empfehle auch die Verwendung der Miniaturansicht von PIL, da dadurch alle Probleme mit dem Verhältnis von Ihnen beseitigt werden.

Ein wichtiger Hinweis: Ersetzen

im.thumbnail(size)

mit

im.thumbnail(size,Image.ANTIALIAS)

Standardmäßig verwendet PIL den Filter Image.NEAREST zum Ändern der Größe, was zu einer guten Leistung, aber einer schlechten Qualität führt.


2
Mit dieser Option können Sie nur die Größe eines Bildes verringern. Es ist nicht möglich, die Größe mit zu erhöhen Image.thumbnail.
Burny

45

Basierend auf @tomvon habe ich Folgendes verwendet (wählen Sie Ihren Fall aus):

a) Größe ändern ( ich kenne die neue Breite, daher brauche ich die neue Höhe )

new_width  = 680
new_height = new_width * height / width 

b) Größenänderung der Breite ( Ich kenne die neue Höhe, daher benötige ich die neue Breite )

new_height = 680
new_width  = new_height * width / height

Dann einfach:

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

6
Ihre Variablen sind alle verwechselt. In Ihrem Beitrag wird die Größe der Breite und anschließend die Größe geändert. Und im resizeAnruf verwenden Sie die new_widthsowohl für Höhe als auch für Breite?
Zachafer

Vorgeschlagene Lösung für das @Zachafer
Mo Beigi

1
Konvertieren Sie sie besser in eine Ganzzahl
Black Thunder

18

PIL hat bereits die Möglichkeit, ein Bild zuzuschneiden

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

20
Dadurch wird nur das Bild zugeschnitten, das Seitenverhältnis wird nicht beibehalten.
Radu

2
Dies beantwortet die Frage in keiner Weise.
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
Dadurch bleibt das Seitenverhältnis des Quellbilds nicht erhalten. Das Bild wird auf 200 x 300 erzwungen und führt zu einem zusammengedrückten oder gestreckten Bild.
Burny

Dies beantwortet die Frage in keiner Weise.
AMC

12

Wenn Sie versuchen, das gleiche Seitenverhältnis beizubehalten, würden Sie dann nicht die Größe um einen bestimmten Prozentsatz der Originalgröße ändern?

Zum Beispiel die Hälfte der Originalgröße

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

13
Es könnte sein, dass die Bilder unterschiedliche Größen hatten und das Größenänderungsergebnis eine einheitliche Größe haben musste
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))

Ich benutze diese Bibliothek:

pip install python-resize-image

7

Wenn Sie das Bild nicht mit Pillow öffnen möchten / müssen, verwenden Sie Folgendes:

from PIL import Image

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

4

Aktualisieren Sie diese Frage einfach mit einem moderneren Wrapper. Diese Bibliothek umschließt Pillow (eine Abzweigung von PIL). Https://pypi.org/project/python-resize-image/

So können Sie Folgendes tun: -

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()

Weitere Beispiele finden Sie im obigen Link.


3
resize_contain sieht eigentlich ganz nützlich aus!
Anytoe

4

Ich habe versucht, die Größe einiger Bilder für ein Diashow-Video zu ändern, und aus diesem Grund wollte ich nicht nur eine maximale Dimension, sondern auch eine maximale Breite und eine maximale Höhe (die Größe des Videorahmens).
Und es gab immer die Möglichkeit eines Porträtvideos ...
DieImage.thumbnail Methode war vielversprechend, aber ich konnte es nicht zu einem kleineren Bild machen.

Nachdem ich hier (oder an anderen Orten) keinen offensichtlichen Weg gefunden hatte, dies zu tun, schrieb ich diese Funktion und stellte sie hier für die kommenden ein:

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

Eine einfache Methode, um eingeschränkte Verhältnisse beizubehalten und eine maximale Breite / Höhe zu überschreiten. Nicht die schönste, erledigt aber die Arbeit und ist leicht zu verstehen:

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

Hier ist ein Python-Skript , das diese Funktion verwendet, um die Größenänderung von Batch-Images auszuführen.


3

Habe die Antwort oben von "tomvon" aktualisiert

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')

Arbeite wie ein Zauber! Also vielen Dank!
Denis Savenko

2

Mein hässliches Beispiel.

Funktion Datei abrufen wie: "pic [0-9a-z]. [Erweiterung]", Größe auf 120x120 ändern, Abschnitt in die Mitte verschieben und in "ico [0-9a-z] speichern. [Erweiterung]", arbeitet mit Hochformat und Landschaft:

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

Ich habe die Größe des Bildes so geändert und es funktioniert sehr gut

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

Ich werde auch eine Version der Größenänderung hinzufügen, die das Seitenverhältnis festhält. In diesem Fall wird die Höhe an die Breite des neuen Bildes angepasst , basierend auf dem anfänglichen Seitenverhältnis asp_rat , das float (!) Ist . Um die Breite an die Höhe anzupassen, müssen Sie stattdessen nur eine Zeile kommentieren und die andere in der else- Schleife auskommentieren. Sie werden sehen, wo.

Sie brauchen die Semikolons (;) nicht, ich behalte sie nur, um mich an die Syntax der Sprachen zu erinnern, die ich häufiger verwende.

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");

Und es ist geschafft. Ich habe versucht, es so gut wie möglich zu dokumentieren, damit es klar ist.

Ich hoffe, es könnte jemandem da draußen hilfreich sein!


0

Öffnen Sie Ihre Bilddatei

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

Verwenden Sie die Methode PIL Image.resize (Größe, Resample = 0) , bei der Sie die Größe 2-Tupel (Breite, Höhe) Ihres Bildes ersetzen.

Dadurch wird Ihr Bild in Originalgröße angezeigt:

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

Dadurch wird Ihr Bild in der halben Größe angezeigt:

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

Dadurch wird Ihr Bild in 1/3 der Größe angezeigt:

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

Dadurch wird Ihr Bild in 1/4 der Größe angezeigt:

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

etc etc.


Was ist display()und wo befindet es sich?
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

Sie können die Bildgröße mithilfe des folgenden Codes ändern:

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')
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.