¿Cómo cambio el tamaño de una imagen usando PIL y mantengo su relación de aspecto?
-
07-07-2019 - |
Pregunta
¿Hay una forma obvia de hacer esto que me falta? Solo estoy tratando de hacer miniaturas.
Solución
Definir un tamaño máximo.
Luego, calcule una relación de cambio de tamaño tomando min (maxwidth / width, maxheight / height)
.
El tamaño apropiado es oldsize * ratio
.
Por supuesto, también hay un método de biblioteca para hacer esto: el método Image.thumbnail
.
A continuación se muestra un ejemplo (editado) de la documentación 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
Otros consejos
Este script cambiará el tamaño de una imagen (somepic.jpg) usando PIL (Python Imaging Library) a un ancho de 300 píxeles y una altura proporcional al nuevo ancho. Para ello, determina qué porcentaje de 300 píxeles es del ancho original (tamaño img. [0]) y luego multiplica la altura original (tamaño img. [1]) por ese porcentaje. Cambiar " ancho de base " a cualquier otro número para cambiar el ancho predeterminado de sus imágenes.
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')
También recomiendo usar el método de miniaturas de PIL, porque elimina todas las molestias de la relación.
Sin embargo, una pista importante: reemplazar
im.thumbnail(size)
con
im.thumbnail(size,Image.ANTIALIAS)
de forma predeterminada, PIL utiliza el filtro Image.NEAREST para cambiar el tamaño, lo que resulta en un buen rendimiento, pero de baja calidad.
Basado en @tomvon, terminé de usar lo siguiente:
Ancho de redimensionamiento:
new_width = 680
new_height = new_width * height / width
Altura de cambio de tamaño:
new_height = 680
new_width = new_height * width / height
Entonces solo:
img = img.resize((new_width, new_height), Image.ANTIALIAS)
PIL ya tiene la opción de recortar una imagen
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
Si está tratando de mantener la misma relación de aspecto, ¿no cambiaría el tamaño en algún porcentaje del tamaño original?
Por ejemplo, la mitad del tamaño original
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))
Yo uso esta biblioteca:
pip install python-resize-image
Mi ejemplo feo.
Función get file como: " pic [0-9a-z]. [extension] " ;, redimensionarlos a 120x120, mueve la sección al centro y guardar en " ico [0-9a-z]. [extension ] " ;, funciona con retrato y paisaje:
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 método simple para mantener relaciones restringidas y pasar un ancho / alto máximo. No es el más bonito, pero hace el trabajo y es fácil de entender:
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
Aquí hay un script de Python que utiliza esta función para ejecutar el cambio de tamaño de la imagen por lotes.
Estaba tratando de cambiar el tamaño de algunas imágenes para un video de presentación de diapositivas y debido a eso, quería no solo una dimensión máxima, sino un ancho máximo y una altura máxima (el tamaño del cuadro de video) .
Y siempre existía la posibilidad de un video de retrato ...
El método Image.thumbnail
fue prometedor, pero no pude mejorar la imagen más pequeña.
Entonces, después de que no pude encontrar una manera obvia de hacer eso aquí (o en otros lugares), escribí esta función y la puse aquí para los que vendrán:
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)
Si no desea / no necesita abrir una imagen con Pillow, use esto:
from PIL import Image
new_img_arr = numpy.array(Image.fromarray(img_arr).resize((new_width, new_height), Image.ANTIALIAS))
Cambié el tamaño de la imagen de tal manera y está funcionando muy bien
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)
Simplemente actualizo esta pregunta con un contenedor más moderno Esta biblioteca envuelve Pillow (un tenedor de PIL) https://pypi.org/project/python-resize-image/
Permitiéndole hacer algo como esto: -
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()
Apila más ejemplos en el enlace anterior.