如何使用PIL保存图片?

156

我刚刚使用Python图像库(PIL)进行了一些图像处理,使用我之前找到的一篇文章来执行图像的傅里叶变换,但我无法让保存函数正常工作。整个代码都可以运行,但它只是无法保存生成的图像:

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

我收到的错误信息如下:

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

如何使用Python的PIL保存图像?

5个回答

186

文件扩展名错误已被处理,您可以使用BMP(不带句点),或者直接传递已包含扩展名的输出名称。现在要处理该错误,您需要正确地修改您在频域中保存为整数图像的数据,PIL告诉您它不接受浮点数据以另存为BMP。

这里有一个建议(还包括其他细微修改,例如使用fftshiftnumpy.array代替numpy.asarray)用于进行正确可视化的转换:

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

@user1999274,主要区别在于使用fft2而不是rfft2,因为对于离散数据,我认为使用后者没有意义。其余部分纯粹是外观上的差异,即如果不应用对数因子,则无法正确可视化傅里叶变换。然后,规范化是为了使转换到范围[0, 255]变得简单。 - mmgp
1
如果visual没有方差(不太可能,但值得注意),则visual = (visual - visual.min()) / (visual.max() - visual.min())将默认执行。 - user1415946
1
我尝试使用这段代码解决我的问题,但是我得到的是纯黑色的图像。有人对此有什么想法吗? http://stackoverflow.com/questions/24266000/using-python-to-save-a-jpg-image-that-was-edited-in-the-script/24266283#24266283 - user961627

42

你应该能够轻松地让PIL从文件扩展名中获取文件类型,即使用:

j.save("C:/Users/User/Desktop/mesh_trans.bmp")

1
感谢您的输入。然而,当我尝试像您上面建议的那样让保存函数获取文件类型时,我遇到了以下错误:IOError: cannot write mode F as BMP。有什么建议吗? - user1999274
2
是的,你应该将数组转换为 numpy.uint8 数据类型而不是浮点数。 - wim

6
尝试移除 . .bmp之前(它没有像预期的那样匹配BMP)。从错误中可以看出,save_handler将您提供的format大写,并在SAVE中寻找匹配项。但是,在该对象中对应的键是BMP(而不是.BMP)。
我不太了解PIL,但从一些快速搜索中可以看出,这是图像mode的问题。将j的定义更改为:
j = Image.fromarray(b, mode='RGB')

对我来说似乎有效(但请注意,我对PIL的了解很少,因此建议使用@mmgp的解决方案,因为他/她显然知道自己在做什么 :))。对于mode类型,我使用了这个页面 - 希望那里的选择之一适合您。


我尝试将“.bmp”更改为“bmp”,但仍然无法正常工作。现在出现的错误是:IOError:无法将模式F写入BMP。我查看了PIL页面以获取文档,并发现应该使用“.bmp”,因此我仍然不知道为什么它无法正常工作。 - user1999274
@user1999274发布了一个更新,对我来说似乎起作用了(抱歉缺少细节 - 我正在一步步拼凑中 :))。 - RocketDonkey
@RocketDonkey 它必须要比那聪明一些,因为将傅里叶变换的结果转换为 RGB 颜色空间会给出一个无意义的图像。仅仅因为它不再引发异常,这并不意味着结果是正确的。 - mmgp
@mmgp 同意 - 这就是为什么我点赞了你的回答并希望楼主接受它的原因 :) - RocketDonkey

4

我知道这是旧的方法,但是在使用Pillow时,通过使用open(fp, 'w')打开文件,然后保存文件会起作用。例如:

with open(fp, 'w') as f:
    result.save(f)
< p >fp 是文件路径,当然了。


1
Pillow的文档指出,如果在save中使用文件对象,则应使用format参数。这不是必需的吗? - Rob Rose
@RobRose 在我的测试中,当我发布答案时,我没有发现有必要这样做。然而,现在可能是这种情况。如果您进行的任何测试证明有必要,请告诉我,我会编辑我的答案。 - Code Enjoyer
1
模式应该是'wb'以存储字节。 - Ivan De Paz Centeno

0

这是我使用PIL导入和导出bmp图像的方法。

def read_img(path):
   """
   Read image and store it as an array, given the image path. 
   Returns the 3 dimensional image array.
   """
   img = Image.open(path)
   img_arr = np.array(img, dtype='int32')
   img.close()
   return img_arr


def write_image(arr, filename):
   """
   write the image
   input : 3 dimensional array
   """
   path = "output/" + filename + ".bmp"
   arr = arr.astype(dtype='uint8')
   img = Image.fromarray(arr, 'RGB')
   img.save(path)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接