Come posso ridimensionare un'immagine usando PIL e mantenerne le proporzioni?
-
07-07-2019 - |
Domanda
C'è un modo ovvio per farlo che mi manca? Sto solo cercando di creare miniature.
Soluzione
Definisce 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 farlo: 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
Altri suggerimenti
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 la percentuale di 300 pixel della larghezza originale (img.size [0]) e quindi moltiplicando l'altezza originale (img.size [1]) per quella percentuale. Modifica " basewidth " a qualsiasi altro numero per modificare la larghezza predefinita delle 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')
Consiglio anche di usare il metodo delle miniature PIL, perché rimuove tutti i fastidi del rapporto da te.
Un suggerimento importante, però: Sostituisci
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à.
Basato su @tomvon, ho finito di usare quanto segue:
Larghezza ridimensionamento:
new_width = 680
new_height = new_width * height / width
Altezza di ridimensionamento:
new_height = 680
new_width = new_height * width / height
Quindi solo:
img = img.resize((new_width, new_height), Image.ANTIALIAS)
PIL ha già la possibilità di ritagliare un'immagine
img = ImageOps.fit(img, size, Image.ANTIALIAS)
from PIL import Image
img = Image.open('/your iamge 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 u want ,*.png,*jpg,*.gif
Se stai cercando di mantenere le stesse proporzioni, non ridimensioneresti di una percentuale della dimensione originale?
Ad esempio, metà delle dimensioni originali
half = 0.5
out = im.resize( [int(half * s) for s in im.size] )
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
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 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:])
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 un script python che utilizza questa funzione per eseguire il ridimensionamento delle immagini in batch.
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 (la dimensione del fotogramma video) .
E c'era sempre la possibilità di un video ritratto ...
Il metodo Image.thumbnail
era promettente, ma non sono riuscito a renderlo di livello superiore a un'immagine più piccola.
Quindi dopo che non sono riuscito a trovare un modo ovvio per farlo qui (o in altri posti), 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)
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))
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)
Sto solo aggiornando questa domanda con un wrapper più moderno Questa libreria avvolge Pillow (una forcella di PIL) https://pypi.org/project/python-resize-image/
Ti consente 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.