ฉันจะเปลี่ยนขนาดรูปภาพโดยใช้ PIL และรักษาอัตราส่วนภาพได้อย่างไร


437

มีวิธีชัดเจนในการทำสิ่งนี้ที่ฉันขาดหายไปหรือไม่? ฉันแค่พยายามสร้างภาพขนาดย่อ


9
เนื่องจากคำถามนี้ค่อนข้างเก่า แต่ก็มีประโยชน์และหมอนค่อนข้างจะดีกว่าสำหรับการสอนด้วยหมอนอิงดูที่นี่: pillow.readthedocs.org/en/latest/handbook/…
Wtower

3
ฉันได้สร้างห้องสมุดขนาดเล็กสำหรับปรับขนาดรูปภาพมันสามารถช่วยได้บ้าง: github.com/charlesthk/python-resize-image
Charlesthk

การเปิดตัวครั้งสุดท้ายของ PIL คือในปีพ. ศ. 2549 หมอนบรรจุภัณฑ์เป็นการทดแทนเท่าที่ฉันรู้ การวางจำหน่ายล่าสุดของหมอนคือ 2 เมษายน 2020
David Medinets

คำตอบ:


477

กำหนดขนาดสูงสุด min(maxwidth/width, maxheight/height)จากนั้นคำนวณอัตราส่วนโดยการปรับขนาด

oldsize*ratioขนาดที่เหมาะสมคือ

มีหลักสูตรนี้ยังมีวิธีการที่จะทำห้องสมุดนี้: Image.thumbnailวิธีการ
ด้านล่างนี้เป็น (แก้ไข) ตัวอย่างเช่นจากเอกสาร 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
อย่างที่มันบอกว่าตัวอย่างนั้นมาจากเอกสารประกอบของ pil และตัวอย่าง (ยัง) ไม่ได้ใช้ธง antialias เนื่องจากอาจเป็นสิ่งที่คนส่วนใหญ่ต้องการ แต่ฉันเพิ่ม
gnud

3
PIL ตั้งค่าความสูงของภาพใหม่เป็นขนาดที่กำหนด (128 ที่นี่) และคำนวณความกว้างเพื่อรักษาอัตราส่วนภาพ มีวิธีแก้ไขความกว้างแทนความสูงหรือไม่? บางทีฉันจะถามคำถามนี้แยกต่างหาก
eugene

6
@Eugene: ลองทำอะไรเช่นนี้s= img.size(); ratio = MAXWIDTH/s[0]; newimg = img.resize((s[0]*ratio, s[1]*ratio), Image.ANTIALIAS)? (ที่สำหรับลอยส่วนจุดแม้ว่า :)
gnud

48
โปรดทราบว่าANTIALIASจะไม่เป็นที่ต้องการอีกต่อไปสำหรับผู้ใช้ Pillow fork ยอดนิยมของ PIL pillow.readthedocs.org/en/3.0.x/releasenotes/…
Joshmaker

8
เอกสาร Python 3 สำหรับ PILบอกว่าthumbnailใช้งานได้หากภาพผลลัพธ์มีขนาดเล็กกว่าภาพต้นฉบับ ด้วยเหตุนี้ฉันจึงเดาว่าการใช้resizeเป็นวิธีที่ดีกว่า
ดังนั้น

253

สคริปต์นี้จะปรับขนาดรูปภาพ (somepic.jpg) โดยใช้ PIL (Python Imaging Library) ให้มีความกว้าง 300 พิกเซลและความสูงตามสัดส่วนกับความกว้างใหม่ ทำได้โดยกำหนดเปอร์เซ็นต์ของพิกเซล 300 เท่าของความกว้างดั้งเดิม (img.size [0]) แล้วคูณความสูงดั้งเดิม (img.size [1]) ด้วยเปอร์เซ็นต์นั้น เปลี่ยน "basewidth" เป็นตัวเลขอื่น ๆ เพื่อเปลี่ยนความกว้างเริ่มต้นของรูปภาพของคุณ

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
หากคุณใช้สคริปต์นี้ใน Zope เป็นวิธีการภายนอกคุณจะต้องใช้บรรทัด "จาก PIL นำเข้ารูปภาพ" เพื่อหลีกเลี่ยงการปะทะกันของเนมสเปซด้วย "รูปภาพ" ของ Zope
tomvon

sompic.jpgรหัสนี้ได้รับฉันไฟล์ที่ส่งออก 0 ไบต์ ทำไมสิ่งนี้ถึงเกิดขึ้น ฉันใช้ Python 3.x
imrek

- อัปเดต: สิ่งเดียวกันนี้เกิดขึ้นใน Python 2.7
imrek

ฉันอาจจะคิดออก หากคุณกำลังประหยัดการใช้.jpeg img.save('sompic.jpg', 'JPEG')
imrek

5
จู้จี้: ไม่มีPIL.Image.ANTIALIASตัวเลือกสำหรับการresizeจริงควรจะPIL.Image.LANCZOSแม้ว่าพวกเขาจะมีทั้ง1ในค่าดูpillow.readthedocs.io/en/3.1.x/reference/...
เฟร็ดวู

66

ฉันยังแนะนำให้ใช้วิธีการแสดงภาพย่อของ PIL เพราะมันจะลบอัตราส่วนทั้งหมดที่ยุ่งยากออกจากตัวคุณ

หนึ่งคำใบ้สำคัญ: แทนที่

im.thumbnail(size)

กับ

im.thumbnail(size,Image.ANTIALIAS)

โดยค่าเริ่มต้น PIL จะใช้ตัวกรอง Image.NEAREST เพื่อปรับขนาดซึ่งทำให้ได้ประสิทธิภาพที่ดี แต่คุณภาพต่ำ


2
ด้วยวิธีนี้คุณสามารถลดขนาดของรูปภาพได้เท่านั้น Image.thumbnailมันเป็นไปไม่ได้ที่จะเพิ่มขนาดด้วย
ไหม้

45

ตาม @tomvon ฉันใช้คำสั่งต่อไปนี้ (เลือกเคสของคุณ):

a) การปรับขนาดความสูง ( ฉันทราบความกว้างใหม่ดังนั้นฉันต้องการความสูงใหม่ )

new_width  = 680
new_height = new_width * height / width 

b) การปรับขนาดความกว้าง ( ฉันทราบความสูงใหม่ดังนั้นฉันต้องการความกว้างใหม่ )

new_height = 680
new_width  = new_height * width / height

จากนั้นเพียง:

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

6
ตัวแปรของคุณผสมกันหมด โพสต์ของคุณบอกว่าปรับขนาดความกว้างแล้วปรับขนาดความสูง และในการresizeโทรคุณใช้new_widthทั้งความสูงและความกว้างใช่ไหม
Zachafer

แนะนำการแก้ไขสำหรับ @Zachafer
Mo Beigi

1
ดีกว่าแปลงให้เป็นจำนวนเต็ม
Black Thunder

18

PIL มีตัวเลือกในการครอบตัดรูปภาพแล้ว

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

20
เพียงแค่ครอบตัดภาพก็ไม่ได้รักษาอัตราส่วนกว้างยาว
Radu

2
สิ่งนี้ไม่ตอบคำถาม แต่อย่างใด
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
นี่ไม่ได้รักษาอัตราส่วนภาพของภาพต้นฉบับ มันบังคับให้ภาพถึง 200x300 และจะส่งผลให้ภาพบีบหรือขยาย
ไหม้

สิ่งนี้ไม่ตอบคำถาม แต่อย่างใด
AMC

12

หากคุณพยายามรักษาอัตราส่วนกว้างยาวเหมือนเดิมคุณจะไม่ปรับขนาดตามขนาดดั้งเดิมบางส่วนใช่หรือไม่

ตัวอย่างเช่นครึ่งหนึ่งของขนาดดั้งเดิม

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

13
อาจเป็นได้ว่ารูปภาพมีขนาดแตกต่างกันและผลลัพธ์การปรับขนาดต้องมีขนาดสม่ำเสมอ
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))

ฉันใช้ห้องสมุดนี้:

pip install python-resize-image

7

หากคุณไม่ต้องการ / ไม่จำเป็นต้องเปิดภาพด้วยหมอนให้ใช้สิ่งนี้:

from PIL import Image

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

4

เพียงแค่อัปเดตคำถามนี้ด้วย wrapper ที่ทันสมัยกว่าห้องสมุดนี้ล้อมรอบ Pillow (ส้อม PIL) https://pypi.org/project/python-resize-image/

อนุญาตให้คุณทำสิ่งนี้: -

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

กองตัวอย่างเพิ่มเติมในลิงค์ด้านบน


3
resize_contain ดูเหมือนมีประโยชน์จริง ๆ !
Anytoe

4

ฉันพยายามปรับขนาดภาพบางส่วนสำหรับวิดีโอสไลด์โชว์และด้วยเหตุนี้ฉันจึงไม่ต้องการมิติสูงสุดเพียงมิติเดียว แต่มีความกว้างสูงสุดและความสูงสูงสุด (ขนาดของกรอบวิดีโอ)
และมีความเป็นไปได้เสมอของวิดีโอภาพที่ ...
Image.thumbnailวิธีการได้รับการสัญญาว่า แต่ฉันไม่สามารถทำให้มันหรูภาพที่มีขนาดเล็ก

ดังนั้นหลังจากที่ฉันไม่สามารถหาวิธีที่ชัดเจนในการทำที่นี่ (หรือที่อื่น ๆ ) ฉันเขียนฟังก์ชันนี้และวางไว้ที่นี่เพื่อให้คนอื่นมา:

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

วิธีง่ายๆในการรักษาอัตราส่วนที่ จำกัด และผ่านความกว้าง / ความสูงสูงสุด ไม่ใช่คนที่สวยที่สุด แต่ทำงานให้เสร็จและเข้าใจง่าย:

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

นี่คือสคริปต์หลามที่ใช้ฟังก์ชันนี้เพื่อปรับขนาดภาพเป็นชุด


3

ได้อัปเดตคำตอบข้างต้นโดย "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')

ทำงานเหมือนจับใจ! ขอบคุณมาก!
Denis Savenko

2

ตัวอย่างที่น่าเกลียดของฉัน

ฟังก์ชั่นรับไฟล์ที่ชอบ: "pic [0-9a-z]. [extension]", ปรับขนาดเป็น 120x120, ย้ายส่วนไปที่กึ่งกลางและบันทึกเป็น "ico [0-9a-z] [extension]", ทำงานร่วมกับ portrait และภูมิทัศน์:

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

ฉันปรับขนาดภาพในลักษณะนี้และทำงานได้ดีมาก

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

ฉันจะเพิ่มเวอร์ชันของการปรับขนาดที่ทำให้อัตราส่วนภาพคงที่ ในกรณีนี้มันจะปรับความสูงให้ตรงกับความกว้างของภาพใหม่โดยอิงจากอัตราส่วนภาพเริ่มต้นคือasp_ratซึ่งเป็นแบบลอย (!) แต่หากต้องการปรับความกว้างเป็นความสูงแทนคุณเพียงแค่ต้องคอมเมนต์หนึ่งบรรทัดและไม่ใส่เครื่องหมายข้อคิดเห็นอื่นในลูปอื่น คุณจะเห็นที่ไหน

คุณไม่จำเป็นต้องใช้เครื่องหมายอัฒภาค (;) ฉันเก็บไว้เพียงเพื่อเตือนตัวเองว่าฉันใช้ไวยากรณ์บ่อยขึ้น

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

และมันจะทำ ฉันพยายามจัดทำเอกสารให้มากที่สุดเท่าที่จะทำได้เพื่อให้ชัดเจน

ฉันหวังว่ามันจะเป็นประโยชน์กับใครบางคนที่นั่น!


0

เปิดไฟล์รูปภาพของคุณ

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

ใช้วิธี PIL Image.resize (ขนาด resample = 0)ซึ่งคุณสามารถแทนที่ (ความกว้างความสูง) ของรูปภาพของคุณเป็นขนาด 2-tuple

นี่จะแสดงภาพของคุณในขนาดดั้งเดิม:

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

นี่จะแสดงรูปภาพของคุณที่ขนาด 1/2:

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

สิ่งนี้จะแสดงภาพของคุณที่ขนาด 1/3:

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

สิ่งนี้จะแสดงภาพของคุณในขนาด 1/4:

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

ฯลฯ


คืออะไรdisplay()และมันเป็นที่ที่ตั้งอยู่ที่ไหน?
แอนโธนี

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

คุณสามารถปรับขนาดภาพตามรหัสด้านล่าง:

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')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.