PIL kullanarak bir görüntüyü nasıl yeniden boyutlandırabilir ve görüntü oranını nasıl koruyabilirim?


437

Bunu yapmanın bariz bir yolu var mı? Sadece küçük resimler yapmaya çalışıyorum.


9
Bu soru oldukça eski ama kullanışlı olduğundan ve yastık daha çok tercih edildiğinden, yastık tabanlı bir öğretici için şuna bir göz atın: pillow.readthedocs.org/en/latest/handbook/…
Wtower

3
Görüntüleri yeniden boyutlandırmak için küçük bir kütüphane oluşturdum, herhangi bir yardımcı olabilir: github.com/charlesthk/python-resize-image
Charlesthk

PIL'in son sürümü 2006 yılındaydı. Yastık packge bildiğim kadarıyla değiştirildi.
Pillow'in

Yanıtlar:


477

Maksimum boyut tanımlayın. Ardından, alarak bir yeniden boyutlandırma oranı hesaplayın min(maxwidth/width, maxheight/height).

Uygun boyut oldsize*ratio.

Elbette bunu yapmak için bir kütüphane yöntemi de vardır: yöntem Image.thumbnail.
Aşağıda PIL belgelerinden (düzenlenmiş) bir örnek verilmiştir .

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
Dediği gibi, örnek pil belgelerinden alınmıştır ve bu örnek (yine de) kenar yumuşatma bayrağını kullanmamaktadır. Muhtemelen çoğu insanın isteyeceği şey olduğu için ekledim.
gnud

3
PIL, yeni görüntünün yüksekliğini verilen boyuta (burada 128) ayarlar ve en boy oranını korumak için genişliği hesaplar. Yükseklik yerine genişliği düzeltmenin bir yolu var mı? belki bunu ayrı bir soruda soracağım.
eugene

6
@Eugene: Gibi bir şey denemek ister misiniz s= img.size(); ratio = MAXWIDTH/s[0]; newimg = img.resize((s[0]*ratio, s[1]*ratio), Image.ANTIALIAS)? (bu kayan nokta bölümü için :)
gnud

48
ANTIALIASPIL'in popüler Yastık çatalı kullanıcıları için artık tercih edilmediğini unutmayın . pillow.readthedocs.org/en/3.0.x/releasenotes/…
Joshmaker

8
PIL için Python 3 belgeleri , thumbnailyalnızca elde edilen görüntü orijinal görüntüden küçükse çalışır. Bu yüzden kullanmanın resizedaha iyi bir yol olduğunu tahmin ediyorum .
Yani

253

Bu komut dosyası, PIL (Python Imaging Library) kullanarak bir görüntüyü (somepic.jpg) 300 piksel genişliğe ve yeni genişliğe orantılı bir yüksekliğe yeniden boyutlandıracaktır. Bunu, orijinal genişliğin (img.size [0]) yüzde 300 pikseli belirleyerek ve sonra orijinal yüksekliği (img.size [1]) bu yüzde ile çarparak yapar. Resimlerinizin varsayılan genişliğini değiştirmek için "taban genişliğini" başka bir sayıyla değiştirin.

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
Bu komut dosyasını Zope'de Harici bir yöntem olarak kullanıyorsanız, Zope'nin "Görüntüsü" ile ad alanı çakışmasını önlemek için "PIL import Image" satırına ihtiyacınız olacaktır.
tomvon

Bu kod bana 0 bayt çıktı dosyası alır sompic.jpg. Bu neden oluyor? Python 3.x kullanıyorum
imrek

- Güncelleme: Python 2.7'de de olur.
imrek

Anladım belki. Bir tasarruf ediyorsanız .jpeg, kullanın img.save('sompic.jpg', 'JPEG').
imrek

5
nit: Her ikisi de değerli olmasına rağmen aslında olması gereken bir PIL.Image.ANTIALIASseçenek yok , bkz. pillow.readthedocs.io/en/3.1.x/reference/…resizePIL.Image.LANCZOS1
Fred Wu

66

Ayrıca, PIL'in küçük resim yöntemini kullanmanızı öneririm, çünkü tüm oran sorunlarını sizden kaldırır.

Yine de önemli bir ipucu: Değiştirin

im.thumbnail(size)

ile

im.thumbnail(size,Image.ANTIALIAS)

varsayılan olarak, PIL yeniden boyutlandırmak için Image.NEAREST filtresini kullanır ve bu da iyi performansa, ancak düşük kaliteye neden olur.


2
Bununla yalnızca görüntünün boyutunu küçültebilirsiniz. İle boyutunu artırmak mümkün değildir Image.thumbnail.
burny

45

@Tomvon'a dayanarak, aşağıdakileri kullanmayı bitirdim (davanızı seçin):

a) Yüksekliği yeniden boyutlandırma ( yeni genişliği biliyorum, bu yüzden yeni yüksekliğe ihtiyacım var )

new_width  = 680
new_height = new_width * height / width 

b) Genişliği yeniden boyutlandırma ( Yeni yüksekliği biliyorum, bu yüzden yeni genişliğe ihtiyacım var )

new_height = 680
new_width  = new_height * width / height

O zaman sadece:

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

6
Değişkenleriniz karışık. Gönderiniz genişliği yeniden boyutlandırıyor ve ardından yüksekliği yeniden boyutlandırıyor. Ve resizeçağrıda, new_widthhem yükseklik hem de genişlik için mi kullanıyorsunuz ?
Zachafer

Bunun için bir düzeltme önerdi @Zachafer
Mo Beigi

1
Onları tamsayıya dönüştürün
Black Thunder

18

PIL'in zaten bir resmi kırpma seçeneği var

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

20
Bu sadece görüntüyü kırpar, en boy oranını korumaz.
Radu

2
Bu soruya hiçbir şekilde cevap vermiyor.
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
Bu, kaynak görüntünün en boy oranını korumaz. Görüntüyü 200x300 boyutuna zorlar ve sıkıştırılmış veya uzatılmış bir görüntüyle sonuçlanır.
10'da burny

Bu soruya hiçbir şekilde cevap vermiyor.
AMC

12

Aynı en boy oranını korumaya çalışıyorsanız, orijinal boyutunun belirli bir yüzdesine göre yeniden boyutlandırmaz mısınız?

Örneğin, orijinal boyutun yarısı

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

13
Görüntülerin değişen boyutlarda olması ve yeniden boyutlandırma sonucunun düzgün boyutta olması gerekebilir
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))

Bu kütüphaneyi kullanıyorum:

pip install python-resize-image

7

Görüntüyü Yastık ile açmaya gerek duymuyorsanız / ihtiyacınız yoksa, bunu kullanın:

from PIL import Image

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

4

Bu soruyu daha modern bir sarıcı ile güncellemek Bu kütüphane Yastık (PIL çatalı) https://pypi.org/project/python-resize-image/

Böyle bir şey yapmanıza izin verir: -

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

Yukarıdaki bağlantıda daha fazla örnek yığınlar.


3
resize_contain aslında oldukça kullanışlı görünüyor!
Anytoe

4

Bir slayt gösterisi videosu için bazı görüntüleri yeniden boyutlandırmaya çalışıyordum ve bu nedenle sadece bir maksimum boyut değil, aynı zamanda maksimum genişlik ve maksimum yükseklik (video çerçevesinin boyutu) istedim .
Ve her zaman bir portre videonun olasılığı vardı ...
Image.thumbnail yöntemi umut verici oldu, ama lüks küçük bir resim gelemedi.

Bu yüzden (ya da başka yerlerde) bunu yapmanın bariz bir yolunu bulamadım, bu işlevi yazdım ve gelmek için buraya koydum:

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

Kısıtlı oranları tutmak ve maksimum genişlik / yükseklikten geçmek için basit bir yöntem. En güzel değil ama işi yapar ve anlaşılması kolaydır:

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

İşte toplu görüntü yeniden boyutlandırma çalıştırmak için bu işlevi kullanan bir python komut dosyası .


3

Yukarıdaki cevabı "tomvon" ile güncelledik

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

Bir cazibe gibi çalışın! Çok teşekkür ederim!
Denis Savenko

2

Çirkin örneğim.

İşlev dosyası şöyle olsun: "pic [0-9a-z]. [Uzantı]", 120x120 olarak yeniden boyutlandırın, bölümü merkeze taşır ve "ico [0-9a-z]. [Uzantı]" klasörüne kaydeder, portre ile çalışır ve manzara:

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

Görüntüyü bu şekilde yeniden boyutlandırdım ve çok iyi çalışıyor

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

En boy oranını sabit tutan yeniden boyutlandırmanın bir sürümünü de ekleyeceğim. Bu durumda, bu ilk en-boy oranı, temel yeni bir resim genişliğine eşleştirmek için yüksekliği ayarlanır asp_rat olup, şamandıra (!). Ama bunun yerine, sadece bir satır ve yorumsuz diğer yorum yapmak gerekir yüksekliğe genişliğini ayarlamak için başka döngü. Nerede olduğunu göreceksin.

Noktalı virgüllere (;) ihtiyacınız yok, sadece kendime daha sık kullandığım dil sözdizimini hatırlatmak için saklıyorum.

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

Ve yapılır. Elimden geldiğince belgelemeye çalıştım, bu yüzden açık.

Umarım orada birine yardımcı olabilir!


0

Resim dosyanızı açın

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

PIL Image.resize (size, resample = 0) yöntemini kullanın ; burada resminizi 2-demet boyutu için değiştirin (genişlik, yükseklik).

Bu, resminizi orijinal boyutunda görüntüler:

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

Bu, resminizi 1/2 boyutunda görüntüler:

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

Bu, görüntünüzü 1/3 boyutunda görüntüler:

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

Bu, görüntünüzü 1/4 boyutunda görüntüler:

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

vesaire vesaire


Nedir display()ve nerede bulunur?
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

Görüntüyü aşağıdaki kodla yeniden boyutlandırabilirsiniz:

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')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.