Como faço para redimensionar uma imagem usando PIL e manter sua proporção?
-
07-07-2019 - |
Pergunta
Existe uma maneira óbvia de fazer isso que eu estou perdendo? Eu só estou tentando fazer miniaturas.
Solução
Defina um tamanho máximo.
Em seguida, calcular uma escala de redimensionamento tomando min(maxwidth/width, maxheight/height)
.
O tamanho adequado é oldsize*ratio
.
Há, naturalmente, também um método de biblioteca para fazer isso:. A Image.thumbnail
método
Abaixo está um (editado) exemplo do PIL documentação .
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
Outras dicas
Este script irá redimensionar uma imagem (somepic.jpg) usando PIL (Python Imaging Library) para uma largura de 300 pixels e uma altura proporcional à nova largura. Ele faz isso determinando qual a percentagem 300 pixels é de largura original (img.size [0]) e, em seguida, multiplicando a altura original (img.size [1]) por esta percentagem. Change "basewidth" para qualquer outro número para alterar a largura padrão de suas imagens.
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')
Eu também recomendo utilizando o método de miniaturas do PIL, porque remove todas as dificuldades razão de você.
Uma dica importante, porém: Substitua
im.thumbnail(size)
com
im.thumbnail(size,Image.ANTIALIAS)
por padrão, PIL usa o filtro Image.NEAREST para redimensionamento que resulta em um bom desempenho, mas de má qualidade.
Com base em @tomvon, eu terminar de usar o seguinte:
O redimensionamento width:
new_width = 680
new_height = new_width * height / width
altura redimensionamento:
new_height = 680
new_width = new_height * width / height
Em seguida, basta:
img = img.resize((new_width, new_height), Image.ANTIALIAS)
PIL já tem a opção de cortar uma imagem
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 você está tentando manter a mesma proporção, então você não iria redimensionar por alguma porcentagem do tamanho original?
Por exemplo, metade do tamanho 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))
Eu uso esta biblioteca:
pip install python-resize-image
Meu exemplo feio.
Função arquivo get como: "pic [0-9a-z] [extensão].", Redimensioná-las para 120x120, seção move para o centro e salvar para "ico [0-9a-z] [extensão].", trabalha com retrato e paisagem:
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:])
Um método simples para manter relações restritas e passando um máximo largura / altura. Não o mais bonito, mas começa o trabalho feito e é 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
Aqui está um python roteiro que usa essa função para executar o redimensionamento da imagem do grupo.
Eu estava tentando redimensionar algumas imagens para um vídeo slideshow e por causa disso, eu queria não apenas uma dimensão máxima, mas uma largura máxima e a altura máxima (o tamanho do quadro de vídeo) .
E havia sempre a possibilidade de um vídeo retrato ...
O método Image.thumbnail
estava prometendo, mas eu não poderia fazê-lo upscale uma imagem menor.
Então, depois eu não conseguia encontrar uma maneira óbvia de fazer isso aqui (ou em alguns outros lugares), eu escrevi essa função e colocá-lo aqui para os vir:
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 você não quer / não tenho uma necessidade para a imagem aberta com Pillow, use o seguinte:
from PIL import Image
new_img_arr = numpy.array(Image.fromarray(img_arr).resize((new_width, new_height), Image.ANTIALIAS))
Eu resizeed a imagem de tal maneira uma e está funcionando muito bem
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)
Apenas atualizando esta pergunta com um invólucro mais moderno Esta biblioteca envolve Pillow (um fork do PIL) https://pypi.org/project/python-resize-image/
O que lhe permite fazer algo assim: -
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()
Heaps mais exemplos no link acima.