Como posso salvar uma imagem com PIL?

118

Acabei de fazer algum processamento de imagem usando a biblioteca de imagens Python (PIL) usando um post que encontrei anteriormente para realizar transformações de Fourier de imagens e não consigo fazer a função salvar funcionar. Todo o código funciona bem, mas não vai salvar a imagem resultante:

from PIL import Image
import numpy as np

i = Image.open("C:/Users/User/Desktop/mesh.bmp")
i = i.convert("L")
a = np.asarray(i)
b = np.abs(np.fft.rfft2(a))
j = Image.fromarray(b)
j.save("C:/Users/User/Desktop/mesh_trans",".bmp")

O erro que recebo é o seguinte:

save_handler = SAVE[string.upper(format)] # unknown format
    KeyError: '.BMP'

Como posso salvar uma imagem com Pythons PIL?

user1999274
fonte

Respostas:

143

O erro referente à extensão do arquivo foi resolvido, ou você usa BMP(sem o ponto) ou passa o nome de saída já com a extensão. Agora, para lidar com o erro, você precisa modificar adequadamente seus dados no domínio da frequência para serem salvos como uma imagem inteira,PIL está lhe dizendo que não aceita dados flutuantes para salvar como BMP.

Aqui está uma sugestão (com outras pequenas modificações, como usar fftshifte em numpy.arrayvez de numpy.asarray) para fazer a conversão para visualização adequada:

import sys
import numpy
from PIL import Image

img = Image.open(sys.argv[1]).convert('L')

im = numpy.array(img)
fft_mag = numpy.abs(numpy.fft.fftshift(numpy.fft.fft2(im)))

visual = numpy.log(fft_mag)
visual = (visual - visual.min()) / (visual.max() - visual.min())

result = Image.fromarray((visual * 255).astype(numpy.uint8))
result.save('out.bmp')
mmgp
fonte
1
ei, muito obrigado. funciona perfeitamente agora! agora tudo que tenho que fazer é entender todas as etapas, mas isso não vai ser tão ruim. muito obrigado pela ajuda
user1999274
@ user1999274 a principal diferença está no uso de em fft2vez de, rfft2pois para dados discretos não vejo sentido em usar o último. O resto é puramente cosmético, ou seja, você não seria capaz de visualizar adequadamente a transformada de Fourier sem aplicar um fator de log a ela. Então a normalização é manter as coisas simples para a conversão para o intervalo [0, 255].
mmgp
1
visual = (visual - visual.min()) / (visual.max() - visual.min())será o padrão se visualnão tiver variação (improvável, mas vale a pena capturar)
1
Tentei usar este código para o meu problema, mas obtive imagens em preto simples. Alguém tem alguma ideia sobre isso? stackoverflow.com/questions/24266000/…
user961627
32

Você deve ser capaz de simplesmente deixar o PIL obter o tipo de arquivo da extensão, ou seja, usar:

j.save("C:/Users/User/Desktop/mesh_trans.bmp")
wim
fonte
1
Obrigado pela contribuição. no entanto, quando tento deixar a função salvar obter o tipo de arquivo como você sugeriu acima, recebo o seguinte erro: IOError: não é possível gravar o modo F como BMP. algum conselho?
user1999274
1
Sim, você deve converter a matriz em numpy.uint8dtype em vez de float.
wim
6

Tente remover o .antes de .bmp(não corresponde BMPao esperado). Como você pode ver pelo erro, save_handlerestá colocando em maiúsculas o que formatvocê forneceu e procurando uma correspondência SAVE. No entanto, a chave correspondente nesse objeto é BMP(em vez de .BMP).

Não sei muito sobre PIL , mas de uma busca rápida ao redor parece que é um problema com o modeda imagem. Alterando a definição de jpara:

j = Image.fromarray(b, mode='RGB')

Pareceu funcionar para mim (no entanto, note que tenho muito pouco conhecimento sobre PILisso, então sugiro usar a solução de @mmgp, pois ele / ela sabe claramente o que está fazendo :)). Para os tipos de mode, usei esta página - espero que uma das opções funcione para você.

RocketDonkey
fonte
Tentei remover o .bmp em favor do bmp e ainda não funcionou. o erro que recebo agora é: IOError: não é possível gravar o modo F como BMP. Eu verifiquei as páginas PIL para documentação e disse para usar o .bmp, de modo geral, ainda não tenho ideia de por que não está funcionando.
user1999274
@ user1999274 Postou uma atualização que parecia funcionar para mim (desculpas pela falta de detalhes - juntando as peças à medida que prossigo :)).
RocketDonkey
@RocketDonkey deve ser um pouco mais inteligente do que isso, porque converter os resultados de uma transformação de Fourier em um espaço de cores RGB resultará em uma imagem sem sentido. Só porque não levanta mais uma exceção, não significa que o resultado está correto.
mmgp
@mmgp Concordo - é por isso que marquei o seu com +1 e espero que o OP aceite :)
RocketDonkey
4

Eu sei que isso é antigo, mas descobri que (ao usar o Pillow) abrir o arquivo usando open(fp, 'w')e salvá-lo funcionará. Por exemplo:

with open(fp, 'w') as f:
    result.save(f)

fp sendo o caminho do arquivo, é claro.

pescoço
fonte
1
A documentação do Pillow diz que o formatparâmetro deve ser usado se um objeto de arquivo for usado em save. Isso não é necessário?
Rob Rose
@RobRose durante meus testes, quando postei a resposta, não achei nada parecido necessário. No entanto, pode ser o caso agora. Se algum teste que você fizer for necessário, me avise e eu
editarei